Why don't you create
new Spark.jl?
2015年7月11日
JuliaTokyo#4
@sfchaos
1
自己紹介
■ twitterID: @sfchaos
■ キーワード:

 データマイニング,機械学習,オントロジー,

 R,Python,Perl,C++,Julia

■ 今日はこの言葉を言うためにやって来ました.

 “Why don't you create Spark.jl?”
2
アジェンダ
1. Sparkとは
2. SparkRを使ってみる
3. PySparkを使ってみる
4. JuliaとSparkの連携をめぐる動向
5. まとめとご提案
3
1. Sparkとは
4
Apache Sparkの概要
■ OSSのインメモリ処理の分散並列基盤.

■ RDDという分散コレクションに対して,

map, filter, reduceなどのデータ処理を繰り返して

目的のデータを得る処理モデル.

※ RDD: Resilient Distributed Dataset

■ 2009年,UC Berkeley(当時)のMatei Zaharia氏が

関数プログラミング言語Scalaを用いて開発.
5
Apache Sparkの概要
■ Sparkのコアとなる分散処理エンジン

(Apache Spark Core)
■Spark SQL: SparkのアプリでSQL
■Spark Streaming: ストリーム処理
■MLlib: 機械学習
■GraphX: グラフの処理
6
データ分析でSparkを使用する意義
■ インタラクティブな分析が可能.

■ 並列分散方法などを意識せずに,大規模データ
(~TB級)の処理が可能.

■ 機械学習のアルゴリズムで頻出する反復処理を

高速化.
7
データ分析でSparkを使用する意義
■k平均法などの反復計算で高速化が期待できる.
8
猿田浩輔,「Spark MLlibではじめるスケーラブルな機械学習」,
JJUG ナイトセミナー, 2014年.
http://www.slideshare.net/hadoopxnttdata/spark-m-llib-nttdata
産業界で進むSparkへの投資
■ IBMが3,500人を投入するなど,今後の一層の成長が
有望視される.
9
TechCrunch記事(2015年6月16日)
http://jp.techcrunch.com/2015/06/16/20150615ibm-pours-researchers-and-
resources-into-apache-spark-project/
SparkRのサポートの開始
■ 従来は,Scala, Java, Pythonで記述,実行可能.

■ 先日リリースされたSpark 1.4.0からは

SparkRのサポートを公式に開始.
10
Sparkのインストール
■ Mac/Linuxユーザは,以下のページから落として解
凍するだけ.

http://spark.apache.org/downloads.html
■ Windowsユーザは,qtwiさんのQiitaの記事を参照.

http://qiita.com/qtwi/items/7abcfc53ba9568f20004
11
MLlibとは
■ Sparkで機械学習を実行するライブラリ
■ 残念ながら,Spark 1.4.0のSparkRではMLlibへの

インタフェースは提供されていない.
12
MLlibで利用できるアルゴリズム
■ 線形モデル
■ クラス分類(線形カーネルSVM, ロジスティック回帰)
■ 回帰(最小二乗法,LASSO,リッジ回帰)
■ 決定木
■ 集団学習(ランダムフォレスト,勾配ブースティング)
■ ナイーブベイズ分類器
■ isotonic回帰(等調回帰?)
13
MLlibの参考資料
■ MLlibについては,以下の資料が大変参考になる.
■ MapReduceを用いる問題点の指摘からSparkや
MLlibの処理の概要まで,非常に分かりやすい.
14
猿田浩輔,「Spark MLlibではじめるスケーラブルな機械学習」,
JJUG ナイトセミナー, 2014年.
http://www.slideshare.net/hadoopxnttdata/spark-m-llib-nttdata
予測モデルの構築・検証(ホールドアウト検定)
■訓練データと検証データに分割
15
データ
訓練
データ
検証
データ
モデル
構築
予測
モデル
モデル
検証
検証結果
モデルを評価する
フェーズ
モデルを構築する
フェーズ
Scalaのファイルを覗いてみる
${SPARK_HOME}/examples/src/main/scala/org/apache/spark/examples/mllib/
DecisionTreeRunner.scala
16
object DecisionTreeRunner {
object ImpurityType extends Enumeration {
type ImpurityType = Value
val Gini, Entropy, Variance = Value
}
import ImpurityType._
Scalaのファイルを覗いてみる
${SPARK_HOME}/examples/src/main/scala/org/apache/spark/examples/mllib/
DecisionTreeRunner.scala
17
case class Params(
input: String = null,
testInput: String = "",
dataFormat: String = "libsvm",
algo: Algo = Classification,
maxDepth: Int = 5,
impurity: ImpurityType = Gini,
maxBins: Int = 32,
minInstancesPerNode: Int = 1,
minInfoGain: Double = 0.0,
numTrees: Int = 1,
featureSubsetStrategy: String = "auto",
fracTest: Double = 0.2,
useNodeIdCache: Boolean = false,
checkpointDir: Option[String] = None,
checkpointInterval: Int = 10) extends AbstractParams[Params]
def main(args: Array[String]) {
ランダムフォレストを用いたホールドアウト検定
■ 現状は,あえてSparkRを使う理由はない気がする
18
scala> import org.apache.spark.SparkContext
scala> import org.apache.spark.mllib.tree.RandomForest
scala> import org.apache.spark.mllib.util.MLUtils
scala> import org.apache.spark.mllib.evaluation.BinaryClassificationMetrics
scala> import org.apache.spark.mllib.evaluation.MulticlassMetrics
scala> // データのロード
scala> val sc = new SparkContext("local", "RandomForest")
scala> val data = MLUtils.loadLibSVMFile(sc,
            "data/mllib/sample_libsvm_data.txt")
scala> // 訓練データとテストデータへの分割
scala> val splits = data.randomSplit(Array(0.7, 0.3))
scala> val (trainingData, testData) = (splits(0), splits(1))
ランダムフォレストを用いたホールドアウト検定
■ 現状は,あえてSparkRを使う理由はないかも
19
scala> // ランダムフォレストを用いた予測モデルの構築
scala> val numClasses = 2 // クラス数
scala> val categoricalFeaturesInfo = Map[Int, Int]() // カテゴリ変数の
情報
scala> val numTrees = 500 // 構築する決定木の個数
scala> val featureSubsetStrategy = "auto" // 特徴量選択のアルゴリズム
scala> val impurity = "gini" // 不純度に用いる指標
scala> val maxDepth = 5 // 木の最大の深さ
scala> val maxBins = 32
scala> val model = RandomForest.trainClassifier(trainingData,
      numClasses, categoricalFeaturesInfo, numTrees,
      featureSubsetStrategy, impurity, maxDepth, maxBins)
ランダムフォレストを用いたホールドアウト検定
■ 現状は,あえてSparkRを使う必要はないかも.
20
scala> // テストデータに対する予測モデルの評価
val labelAndPreds = testData.map { point =>
val prediction = model.predict(point.features)
(point.label, prediction)
}
scala> // 混合行列
scala> val metrics = new MulticlassMetrics(labelAndPreds)
scala> metrics.confusionMatrix
res20: org.apache.spark.mllib.linalg.Matrix =
13.0 1.0
0.0 17.0
scala> metrics.precision
res21: Double = 0.9285714
正例と予測
実績が正例
適合率
(precision)
2. SparkRを使ってみる
21
SparkRとは
■ RからSparkを使うためのバインディング
■ Spark 1.4.0から公式にサポートされることになった.
22
SparkRの情報
■ qtwiさんのQiitaの記事が非常にまとまっている.
■ 本資料でも大いに参考にさせていただいた.

http://qiita.com/qtwi/items/7abcfc53ba9568f20004
■ というか,この記事を読んだ方がはるかに良い.
23
SparkRの情報
■@hoxo_mさんの記事

http://qiita.com/hoxo_m/items/
22d31ad589970246562d
24
SparkRのアーキテクチャ
25
Shivaram Venkataraman, Zongheng Yang,
SparkR: Enabling Interactive Data Science at Scale,
https://spark-summit.org/2014/wp-content/uploads/2014/07/SparkR-
SparkSummit.pdf
SparkRの起動
■Sparkのディレクトリ配下のbin/sparkRを実行
■必要に応じてパスを通しておくと良い
26
$ bin/sparkR
R version 3.1.2 (2014-10-31) -- "Pumpkin Helmet"
Copyright (C) 2014 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin13.4.0 (64-bit)
(中略)
Welcome to SparkR!
Spark context is available as sc, SQL context is available as
sqlContext
データの入出力・変換
■ createDataFrame: SparkのDataFrameに変換

※ DataFrameは,SparkSQL用のデータ形式
27
データの入出力・変換
■ jsonファイル
■ read.df関数で読み込みHiveSQL上のテーブルに
変換
■ SQLによりデータ抽出可能
28
> people <- read.df(sqlContext, “./examples/src/main/resources/
> people.json", "json")
> head(people)
## age name
##1 NA Michael
##2 30 Andy
##3 19 Justin
> printSchema(people)
# root
# |-- age: integer (nullable = true)
# |-- name: string (nullable = true)
データの入出力・変換
■ Hiveとの連携
■ HDFSに蓄積されたデータの抽出
29
> hiveContext <- sparkRHive.init(sc)
> sql(hiveContext, "CREATE TABLE IF NOT EXISTS src (key INT, value
STRING)")
> sql(hiveContext, "LOAD DATA LOCAL INPATH ‘examples/src/main/
resources/kv1.txt' INTO TABLE src")
> # クエリはHiveQLで表現可能
> results <- hiveContext.sql("FROM src SELECT key, value")
> # 返り値はRのデータフレームで返される
> head(results)
## key value
## 1 238 val_238
## 2 86 val_86
## 3 311 val_311
DataFrameオブジェクトの作成
■ createDataFrame関数によりRのデータフレームから作成
30
> iris.df <- createDataFrame(sqlContext, iris)
> iris.df
DataFrame[Sepal_Length:double, Sepal_Width:double,
Petal_Length:double, Petal_Width:double, Species:string]
> class(iris.df)
[1] "DataFrame"
attr(,"package")
[1] “SparkR"
> head(iris.df, 3)
Sepal_Length Sepal_Width Petal_Length Petal_Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
DataFrameオブジェクトの操作
■ 行の抽出(filter関数)
31
> library(magrittr)
> head(filter(iris.df, iris.df$Sepal_Length >= 5.0), 3)
Sepal_Length Sepal_Width Petal_Length Petal_Width Species
1 5.1 3.5 1.4 0.2 setosa
2 5.0 3.6 1.4 0.2 setosa
3 5.4 3.9 1.7 0.4 setosa
> # パイプ処理も可能
> iris.df %>% filter(iris.df$Sepal_Length >= 5.0) %>% head(3)
> # NSE(Non Standard Evaluation)は使えない
> iris.df %>% filter(Sepal_Length >= 5.0) %>% head(3)
以下にエラー filter(., Sepal_Length >= 5) :
引数 'condition' の評価中にエラーが起きました (関数 'filter' に対するメソッ
ドの選択時): エラー: オブジェクト 'Sepal_Length' がありません
magrittrパッケージを使用
(dplyrを読み込むと名前の衝突が起きて,
面倒なことに・・・)
データフレームの操作
■ 列の抽出
32
> head(select(iris.df, iris.df$Species), 3)
Species
1 setosa
2 setosa
3 setosa
> # パイプ処理も可能
> iris.df %>% select(iris.df$Species) %>% head(3)
> # NSE(Non Standard Evaluation)は使えない
> iris.df %>% select(Species) %>% head(3)
以下にエラー select(., Species) :
引数 'col' の評価中にエラーが起きました (関数 'select' に対するメソッドの選
択時): エラー: オブジェクト 'Species' がありません
グループ化・集約
■ グループ化処理はgroupBy関数で実行.
■ 集約処理はsummarize関数で実行.
33
> # 列Speciesの種別ごとに件数を集計する
> iris.df %>% groupBy(iris.df$Species) %>%
summarize(count=n(iris.df$Species)) %>% collect
Species count
1 versicolor 50
2 setosa 50
3 virginica 50
SparkRからのランダムフォレストの実行
■ launchBackend関数でScalaやJavaでビルドした関
数を実行するのが良さそう.

※ qtwiさんのqiita記事を参照.
34
> SparkR:::launchBackend(
sparkSubmitOpts=“--class
    org.apache.spark.examples.mllib.DecisionTreeRunner
lib/spark-examples-1.4.0-hadoop2.6.0.jar”,
jars=“",
args="-input data/mllib/sample_libsvm_data.txt -numTrees 500
      -fracTest 0.3”,
sparkHome=Sys.getenv("SPARK_HOME"))
ランダムフォレストの実行例
その他の話題
■ ローカルモードだけでなく,マスター・スレーブを
用いた実行例
■ RStudioからの利用
■ SparkRからのRDDの利用 等々

qtwiさんのqiita記事を参照.
35
3. PySparkを使ってみる
36
PySparkのアーキテクチャ
37
大規模並列処理:PythonとSparkの甘酸っぱい関係∼PyData.Tokyo Meetup #3イベント
レポート
http://codezine.jp/article/detail/8484
PySparkの起動
■ PySparkの起動
38
$ cd $SPARK_HOME/bin
$ ./pyspark
Python 2.7.9 (default, Feb 10 2015, 03:28:08)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
Using Spark's default log4j profile: org/apache/spark/log4j-
defaults.properties
15/07/11 13:35:56 INFO SparkContext: Running Spark version 1.4.0
(中略)
Welcome to
____ __
/ __/__ ___ _____/ /__
_ / _ / _ `/ __/ '_/
/__ / .__/_,_/_/ /_/_ version 1.4.0
/_/
Using Python version 2.7.9 (default, Feb 10 2015 03:28:08)
SparkContext available as sc, HiveContext available as sqlContext.
>>>
MLlibの使用
■ランダムフォレストの実行
39
>>> from pyspark.mllib.tree import RandomForest, RandomForestModel
>>> from pyspark.mllib.util import MLUtils
>>> # データファイルをロードしパースしてLabeledPointのRDDに変換
>>> data = MLUtils.loadLibSVMFile(sc,
... ’../data/mllib/sample_libsvm_data.txt’)
>>> # データを訓練用とテスト用に分割 (テスト用は30%)
>>> (trainingData, testData) = data.randomSplit([0.7, 0.3], seed=123)
>>> # ランダムフォレストを用いた予測モデル構築
>>> model = RandomForest.trainClassifier(
... trainingData, numClasses=2,
... categoricalFeaturesInfo={}, numTrees=3,
... featureSubsetStrategy=‘auto’, impurity='gini',
... maxDepth=4, maxBins=32)
>>> # テストデータに対してモデルを評価し,誤差を算出
>>> predictions = model.predict(testData.map(lambda x: x.features))
>>> labelsAndPredictions = testData.map(
... lambda lp: lp.label).zip(predictions)
>>> testErr = labelsAndPredictions.filter(
... lambda (v, p): v != p).count() / float(testData.count())
>>> print('Test Error = ' + str(testErr))
>>> print('Learned classification forest model:')
>>> print(model.toDebugString())
自然な記述が可能
4. JuliaとSparkの

 連携をめぐる動向
40
JuliaとSparkの連携
■ Spark.jl : JuliaでRDDの実装.
■ RPC(Remote Procedure Call)でJVMと連携.
41
https://github.com/d9w/Spark.jl
JuliaとSparkの連携
■ Spark.jlはRDDの実装が正しくない?
42
JuliaとSparkの連携
■ とりあえずインストール
43
$ julia
julia> Pkg.clone("https://github.com/d9w/Spark.jl.git")
INFO: Cloning Spark from https://github.com/d9w/Spark.jl.git
INFO: Computing changes...
JuliaとSparkの連携
■ とりあえずサンプルコードの実行
44
$ julia
julia> using Spark
julia> # マスターサーバ
julia> master = Spark.Master("127.0.0.1", 3333)
julia> # ワーカーサーバの起動
julia> # Spark.load(master, “default_workers.json")
julia> # マスターサーバーの初期化
julia> Spark.initserver(master)
julia> # RDDの生成と操作
julia> # 整数が並んだデータを読みこむ
julia> rdd = Spark.input(master, "RDDA.txt", "int_reader")
julia> filtered_rdd = Spark.filter(master, rdd, "number_filter")
julia> results = Spark.collect(master, filtered_red)
0-element Array{Any,1}
1
2
…
10
!!!原因究明中
JuliaとSparkの連携
■ 他にも Spock.jl や Sparta.jl などがある.
45
Spock.jl
Sparta.jl
https://groups.google.com/forum/m/#!msg/julia-dev/-Ft7jaHLAec/ZfLo9uTAP1cJ
JuliaとSparkの連携
■ セグフォ(Segmentation Fault)が難関?
46
https://groups.google.com/forum/m/#!msg/julia-dev/-Ft7jaHLAec/ZfLo9uTAP1cJ
Spock.jl
■ Jey Kottalam(カリフォルニア大学バークレー校)が
開発.
■ JavaCall.jl を用いてJuliaからJavaのコードを呼ぶ.
47
https://github.com/jey/Spock.jl
Spock.jl
■ インストールとサンプルプログラムの実行
48
$ julia
julia> Pkg.clone(“https://github.com/jey/Spock.jl.git")
julia> quit()
$ cd $HOME/.julia/v0.3/Spock/
$ ln -s /usr/local/share/spark/lib/spark-assembly-1.4.0-
hadoop2.6.0.jar lib/spark.jar
$ make
mkdir -p build
javac -Xlint -d build -cp lib/spark.jar: src//JuliaFunction.java
src//JuliaObject.java
jar cf lib/spock.jar -C build .
julia test/runtests.jl 2> stderr.log
Loaded /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/
Contents/Home/jre/lib/server/libjvm.dylib
Spock.jl
■ サンプルプログラムの実行
49
julia> using Spock
julia> using Base.Test
julia> sc = SparkContext()
julia> rdd1 = parallelize(sc, 1:10, 2)
julia> collect(rdd1)
10-element Array{Int64,1}:
1
2
3
4
5
6
7
8
9
10
Sparta.jl
■ Andrei Zhabinski氏が開発しているライブラリ.
■ Pysparkを移植しようとしている.
50
https://github.com/dfdx/Sparta.jl
Sparta.jl
■ これも多分,RPCでJVMと連携.
51
using JavaCall
JList = @jimport java.util.List
JArrays = @jimport java.util.Arrays
JJuliaRDD = @jimport org.apache.spark.api.julia.JuliaRDD
JJavaRDD = @jimport org.apache.spark.api.java.JavaRDD
JJavaRDD_ = @jimport "org.apache.spark.api.java.JavaRDD$"
JRDD = @jimport org.apache.spark.rdd.RDD
JJavaSparkContext = @jimport
org.apache.spark.api.java.JavaSparkContext
Sparta.jl
52
https://groups.google.com/forum/m/#!msg/julia-dev/-Ft7jaHLAec/ZfLo9uTAP1cJ
現時点ではほとんど空だけど
すぐに戻ってきて進めるよ
(6月19日)
45%完了!!(7月11日時点)
https://github.com/dfdx/Sparta.jl
Sparta.jl
■ githubからインストール.
53
julia> Pkg.clone("https://github.com/dfdx/Sparta.jl.git")
INFO: Cloning Sparta from https://github.com/dfdx/Sparta.jl.git
INFO: Computing changes...
INFO: No packages to install, update or remove
INFO: Package database updated
Sparta.jl
■ パッケージの読み込み
54
julia> using Sparta
Loaded /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/
Contents/Home/jre/lib/server/libjvm.dylib
signal (11): Segmentation fault: 11
unknown function (ip: 362844852)
julia> using Sparta せまりくるセグフォの恐怖
Sparta.jl
■ テストを確認してみる.
55
using Sparta
using Base.Test
# write your own tests here
@test 1 == 1
~
test/runtests.jl
5. まとめとご提案
56
まとめ
■ Spock.jl や Sparta.jl などのパッケージ開発中.

■ セグフォ問題: Julia-Spark連携に立ちふさがる壁

■ そこで,
57
“Why don't you create new Spark.jl?”

Why dont you_create_new_spark_jl