Rにおける大規模データ解析 ~bigmemoryパッケージ~ 2011年4月10日 第10回 TokyoWebMining 2nd week @sfchaos
Rにおける大規模データ解析~bigmemoryパッケージ~
2011年4月10日
第10回 TokyoWebMining 2nd week
@sfchaos
2
本発表の趣旨
Rは便利な統計解析ツールとして注目を浴びていますが,大規模なデータを扱うことが得意ではありません.
そこで,本発表では,大規模データを扱うパッケージの一つであるbigmemoryとその兄弟パッケージについて紹介します.
HadoopやMahoutなどを使うほどではなく,かといってRの標準機能だけでは扱いに困るほどの規模のデータを扱う方のお役に立てれば幸いです.
3
アジェンダ
1. 自己紹介
2.Rの長所と短所
3.Rにおける大規模データ管理
4. bigmemoryパッケージを用いた並列計算
5. まとめ
4
アジェンダ
1. 自己紹介
2.Rの長所と短所
3.Rにおける大規模データ管理
4. bigmemoryパッケージを用いた並列計算
5. まとめ
5
自己紹介
TwitterID: @sfchaos
出身地: 埼玉県
職業:コンサルタント 数年間,金融工学のモデル構築・データ解析
最近,大規模データ解析に着手(Hadoop/Mahout)
学生時代の専攻は物理・応用数学(非線形力学系・カオス)
※博士ではありません
6
アジェンダ
1. 自己紹介
2.Rの長所と短所
3.Rにおける大規模データ管理
4. bigmemoryパッケージを用いた並列計算
5. まとめ
7
2.1 Rとは
統計計算とグラフィックスのための言語・環境
多様な統計手法 (線形・非線形モデル、古典的統計検定、時系列解析、判別分析、クラスタリング等) とグラフィックスを提供
フリーソフトであり,近年,大いに注目を集めている
8
2.2 Rの長所(の一例)
ベクトルや行列等のオブジェクトの扱いやすさ> x <- 1:10> x [1] 1 2 3 4 5 6 7 8 9 10> x[x%%2==0] # 偶数番目の要素の取り出し[1] 2 4 6 8 10> y <- matrix(1:10, nrow=2)> y [,1] [,2] [,3] [,4] [,5][1,] 1 3 5 7 9[2,] 2 4 6 8 10> apply(y, 1, mean) # 各行の平均[1] 5 6
9
きれいなグラフィクス
Average Yearly Sunspots
spots
1750 1800 1850 1900 1950
0
50
100
150
Year
spots
050100150
1750 1800 1850 1900 1950
10
最新の手法を用意した豊富なパッケージ群
11
2.3 Rの短所
12
2.3 Rの短所
マルチCPU(コア)の環境でも基本的に1CPU(コア)
13
2.3 Rの短所
マルチCPU(コア)の環境でも基本的に1CPU(コア)
基本的にオンメモリでデータを保持,計算を実行
14
2.3 Rの短所
マルチCPU(コア)の環境でも基本的に1CPU(コア)
基本的にオンメモリでデータを保持,計算を実行
ベクトル,行列,配列などの要素数の上限が231-1
15
2.3 Rの短所
マルチCPU(コア)の環境でも基本的に1CPU(コア)
基本的にオンメモリでデータを保持,計算を実行
ベクトル,行列,配列などの要素数の上限が231-1
基本的にオブジェクトの参照渡しができず値渡しを行うため,コピーがあちこちで発生しメモリを消費する
16
2.3 Rの短所
マルチCPU(コア)の環境でも基本的に1CPU(コア)
基本的にオンメモリでデータを保持,計算を実行
ベクトル,行列,配列などの要素数の上限が231-1
基本的にオブジェクトの参照渡しができず値渡しを行うため,コピーがあちこちで発生しメモリを消費する
大規模なデータを扱ったり計算速度を上げるためには工夫が必要
→高性能計算(High Performance Computing, HPC)
17
アジェンダ
1. 自己紹介
2.Rの長所と短所
3.Rにおける大規模データ管理
4. Bigmemory Project
5. bigmemoryパッケージを用いた並列計算
6. まとめ
18
3.1 RにおけるHPC
並列計算
明示的な並列化
内部的な並列化
グリッドコンピューティング
乱数
リソース管理・バッチスケジューリング
応用
GPU
大規模データ管理
コンパイルコードへの簡便なインタフェース
プロファイリングツール
CRAN Task View: High-Performance and Parallel Computing with Rhttp://cran.r-project.org/index.html
19
3.1 RにおけるHPC
並列計算
明示的な並列化(マルチコア/CPU計算等)
内部的な並列化
グリッドコンピューティング
乱数
リソース管理・バッチスケジューリング
応用
GPU
大規模データ管理(RAMを超えるデータ管理)
コンパイルコードへの簡便なインタフェース
プロファイリングツール
CRAN Task View: High-Performance and Parallel Computing with Rhttp://cran.r-project.org/index.html
20
3.2 大規模データ管理パッケージ
ffとbigmemoryが代表的なパッケージ.
両方のパッケージともバックエンドでC++を使用.
21
3.2 大規模データ管理パッケージ
ff データをディスクに置き,必要に応じてメモリにロードする.
行列,データフレーム,因子など多数のデータ型を用意している.
bigmemory 大規模データをディスク等に置き,必要に応じて物理メモリにキャッシュ
する.
扱えるデータ型は行列のみである.
1台の計算機上で複数のRのプロセスでオブジェクトを共有することが可能である.
22
3.2 大規模データ管理パッケージ
ff データをディスクに置き,必要に応じてメモリにロードする.
行列,データフレーム,因子など多数のデータ型を用意している.
bigmemory 大規模データをディスク等に置き,必要に応じて物理メモリにキャッシュ
する.
扱えるデータ型は行列のみである.
1台の計算機上で複数のRのプロセスでオブジェクトを共有することが可能である.
どちらが優位かについては一概に言えない
23
3.2 大規模データ管理パッケージ
ff データをディスクに置き,必要に応じてメモリにロードする.
行列,データフレーム,因子など多数のデータ型を用意している.
bigmemory 大規模データをディスク等に置き,必要に応じて物理メモリにキャッシュ
する.
扱えるデータ型は行列のみである.
1台の計算機上で複数のRのプロセスでオブジェクトを共有することが可能である.
どちらが優位かについては一概に言えない
24
3.2 大規模データ管理パッケージ
ff データをディスクに置き,必要に応じてメモリにロードする.
行列,データフレーム,因子など多数のデータ型を用意している.
bigmemory 大規模データをディスク等に置き,必要に応じて物理メモリにキャッシュ
する.
扱えるデータ型は行列のみである.
1台の計算機上で複数のRのプロセスでオブジェクトを共有することが可能である.
どちらが優位かについては一概に言えない
並列計算・並行計算が可能に
25
3.3 bigmemoryを用いて解決するRの欠点
欠点 bigmemoryの使用による解決度合い
マルチCPU(コア)の環境でも基本的に1CPU(コア)
○
並列計算,並行計算が可能に
基本的にオンメモリでデータを保持,計算を実行
○
RAMをはるかに超えるデータの扱いが可能に
ベクトル,行列,配列などの要素数の上限が231-1
○
要素数の上限は252まで拡張
基本的にオブジェクトの参照渡しができず値渡しを行うため,コピーがあちこちで発生しメモリを消費する
◎
参照渡しでオブジェクトを渡せる
26
3.4 The bigmemory project
大規模行列の管理/解析/集計を行うパッケージ群
2010年度の米国の統計学会の
統計計算分野で、2010年の
"John M. Chambers Statistical
Software Award"を受賞
次の5つのパッケージで構成される
パッケージ名 機能
bigmemory 大規模行列の管理
biganalytics 大規模行列の解析
bigtabulate 大規模行列の集計
bigalgebra 大規模行列の演算
synchronicity 大規模行列の処理の同期・排他制御
27
3.5 bigmemoryパッケージの基本的な使い方
Data Expo 2009 アメリカの旅客機のフライトデータ(1987年~2008年)
約1億2,300万レコード,29フィールド(約12GB)
28
データの読み込み> library(bigmemory)> airline <- read.big.matrix("AirlineAllData.csv", header=TRUE, sep=",",
backingifle="AirlineAllData.bin", descriptorfile="AirlineAllData.desc")
行列サイズの確認> dim(airline)[1] 123534969 29
行列要素へのアクセス・値の格納 > airline[1:5, 1:5]> airline[1:5, ]> airline[1:5, 1] <- 1986
通常のRの関数を使った場合とほとんど同様に操作できる
29
bigtabulateを用いると,データの要約・集計も可能になる.> library(bigtabulate)
> # 各列の要約(最小値、最大値、平均値、NAの数)
> summary(airline)
> # 年ごと月ごとのフライト数
> bigtable(airline, c("Year", "Month"))
> # 曜日ごとの到着時間の遅れの統計量(最小値、最大値、平均値、標準偏差、NAの数)
> bigtsummary(airline, "DayOfWeek", cols="ArrDelay", na.rm=T)
30
3.6 (ご参考)大規模データを扱うメカニズム
メモリマッピングという技術を用いて,ファイルをメモリのように扱い,必要なときに高速にキャッシュする.
メモリ
ファイル
ディスク
ファイルをメモリのように扱う
ファイルからメモリに
高速キャッシュ
CPU
31
アジェンダ
1. 自己紹介
2.Rの長所と短所
3.Rにおける大規模データ管理
4. bigmemoryパッケージを用いた並列計算
5. まとめ
32
4.1 並列計算とは
ジョブを分割して複数のCPU(orコア)で処理すること
CPU
CPU
CPU
CPU
1CPU(コア)での処理に比べ計算速度が向上
33
4.2 bigmemoryを用いた並列計算
旅客機の製造後の経過年数を推定する問題(Vignette "The Bigmemory Project"に掲載されている例)
> # 1つの旅客機のフライト日から製造された月を推定する関数
> birthmonth <- function(y) {
+ minYear <- min(y[,'Year'], na.rm=TRUE)
+ these <- which(y[,'Year']==minYear)
+ minMonth <- min(y[these,'Month'], na.rm=TRUE)
+ return(12*minYear + minMonth – 1)
+ }
34
普通にやろうとすると・・・> # 旅客機コード
> allplanes <- unique(x[,'TailNum'])
> planeStart <- rep(0, length(allplanes))
> # 各旅客機に対してfor文で製造月を推定
> for (i in allplanes) {
+ planeStart[i] <- birthmonth( x[mwhich(x, 'TailNum', i, 'eq'),
+ c('Year', 'Month'), drop=FALSE])
+ }
35
普通にやろうとすると・・・> # 旅客機コード
> allplanes <- unique(x[,'TailNum'])
> planeStart <- rep(0, length(allplanes))
> # 各旅客機に対してfor文で製造月を推定
> for (i in allplanes) {
+ planeStart[i] <- birthmonth( x[mwhich(x, 'TailNum', i, 'eq'),
+ c('Year', 'Month'), drop=FALSE])
+ }
約9時間!
36
そこで,異なるアプローチで計算を行う> library(bigtabulate)
> # 旅客機コードごとのレコード番号> planeindices <- bigsplit(x, 'TailNum')> library(doMC)> registerDoMC(cores=2)
> # 製造月の推定> planeStart <- + foreach(i=planeindices, .combine=c) %dopar% {+ return(birthmonth(x[i, c('Year','Month'), + drop=FALSE]))+ }
37
そこで,異なるアプローチで計算を行う> library(bigtabulate)
> # 旅客機コードごとのレコード番号> planeindices <- bigsplit(x, 'TailNum')> library(doMC)> registerDoMC(cores=2)
> # 製造月の推定> planeStart <- + foreach(i=planeindices, .combine=c) %dopar% {+ return(birthmonth(x[i, c('Year','Month'), + drop=FALSE]))+ }
14秒!!
38
2コアを使って並列計算
そこで,異なるアプローチで計算を行う> library(bigtabulate)
> # 旅客機コードごとのレコード番号> planeindices <- bigsplit(x, 'TailNum')> library(doMC)> registerDoMC(cores=2)
> # 製造月の推定> planeStart <- + foreach(i=planeindices, .combine=c) %dopar% {+ return(birthmonth(x[i, c('Year','Month'), + drop=FALSE]))+ }
14秒!!
39
2コアを使って並列計算
そこで,異なるアプローチで計算を行う> library(bigtabulate)
> # 旅客機コードごとのレコード番号> planeindices <- bigsplit(x, 'TailNum')> library(doMC)> registerDoMC(cores=2)
> # 製造月の推定> planeStart <- + foreach(i=planeindices, .combine=c) %dopar% {+ return(birthmonth(x[i, c('Year','Month'), + drop=FALSE]))+ }
旅客機ごとにジョブを分割
14秒!!
40
2コアを使って並列計算
そこで,異なるアプローチで計算を行う> library(bigtabulate)
> # 旅客機コードごとのレコード番号> planeindices <- bigsplit(x, 'TailNum')> library(doMC)> registerDoMC(cores=2)
> # 製造月の推定> planeStart <- + foreach(i=planeindices, .combine=c) %dopar% {+ return(birthmonth(x[i, c('Year','Month'), + drop=FALSE]))+ }
旅客機ごとにジョブを分割
旅客機ごとの製造月の推定14秒!!
41
2コアを使って並列計算
そこで,異なるアプローチで計算を行う> library(bigtabulate)
> # 旅客機コードごとのレコード番号> planeindices <- bigsplit(x, 'TailNum')> library(doMC)> registerDoMC(cores=2)
> # 製造月の推定> planeStart <- + foreach(i=planeindices, .combine=c) %dopar% {+ return(birthmonth(x[i, c('Year','Month'), + drop=FALSE]))+ }
旅客機ごとにジョブを分割
旅客機ごとの製造月の推定
結果の集約
14秒!!
42
4.3 split-apply-combine
CPU
CPU
CPU
CPU
43
4.3 split-apply-combine
CPU
CPU
CPU
CPU
2コアを使って並列計算
44
4.3 split-apply-combine
CPU
CPU
CPU
CPU
2コアを使って並列計算
旅客機ごとにジョブを分割
45
4.3 split-apply-combine
CPU
CPU
CPU
CPU
2コアを使って並列計算
旅客機ごとにジョブを分割
旅客機ごとの製造月の推定
46
4.3 split-apply-combine
CPU
CPU
CPU
CPU
2コアを使って並列計算
旅客機ごとにジョブを分割
旅客機ごとの製造月の推定
結果の集約
47
4.3 split-apply-combine
CPU
CPU
CPU
CPU
2コアを使って並列計算
旅客機ごとにジョブを分割
旅客機ごとの製造月の推定
結果の集約
split
48
4.3 split-apply-combine
CPU
CPU
CPU
CPU
2コアを使って並列計算
旅客機ごとにジョブを分割
旅客機ごとの製造月の推定
結果の集約
split apply
49
4.3 split-apply-combine
CPU
CPU
CPU
CPU
2コアを使って並列計算
旅客機ごとにジョブを分割
旅客機ごとの製造月の推定
結果の集約
split apply combine
50
4.3 split-apply-combine
CPU
CPU
CPU
CPU
2コアを使って並列計算
旅客機ごとにジョブを分割
旅客機ごとの製造月の推定
結果の集約
split apply combine
"split-apply-combine"
51
4.4 biganalyticsパッケージにおける実装例
非階層的クラスター分析のk平均法
分析対象のデータ ① 指定したクラスター数個分のクラスター中心をランダムに選ぶ
② 各データに対して最も近い中心を探す
③ 各クラスターに属する点の中心を新たなクラスター中心とする
クラスターが変化しなくなるまで繰り返す
52
4.4 biganalyticsパッケージにおける実装例
K平均法の結果は初期値に大きく依存 → 複数回試行する
分析対象のデータ ① 指定したクラスター数個分のクラスター中心をランダムに選ぶ
② 各データに対して最も近い中心を探す
③ 各クラスターに属する点の中心を新たなクラスター中心とする
クラスターが変化しなくなるまで繰り返す
53
4.4.2 設計方針
bigkmeans <- function (x, centers, iter.max = 10, nstart = 1){
(中略)
ans <- foreach(cen = centers, .combine = "choosebest") %dopar% {
require(biganalytics)
(中略)
if (is.null(xdesc)) {
if (mattype == 4) {
res <- .Call("kmeansRIntMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
} else {
res <- .Call("kmeansRNumericMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
}
}
(以降略)
}
54
bigkmeans <- function (x, centers, iter.max = 10, nstart = 1){
(中略)
ans <- foreach(cen = centers, .combine = "choosebest") %dopar% {
require(biganalytics)
(中略)
if (is.null(xdesc)) {
if (mattype == 4) {
res <- .Call("kmeansRIntMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
} else {
res <- .Call("kmeansRNumericMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
}
}
(以降略)
}
並列計算
55
bigkmeans <- function (x, centers, iter.max = 10, nstart = 1){
(中略)
ans <- foreach(cen = centers, .combine = "choosebest") %dopar% {
require(biganalytics)
(中略)
if (is.null(xdesc)) {
if (mattype == 4) {
res <- .Call("kmeansRIntMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
} else {
res <- .Call("kmeansRNumericMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
}
}
(以降略)
}
並列計算 クラスター中心(split)
56
bigkmeans <- function (x, centers, iter.max = 10, nstart = 1){
(中略)
ans <- foreach(cen = centers, .combine = "choosebest") %dopar% {
require(biganalytics)
(中略)
if (is.null(xdesc)) {
if (mattype == 4) {
res <- .Call("kmeansRIntMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
} else {
res <- .Call("kmeansRNumericMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
}
}
(以降略)
}
並列計算 クラスター中心(split)
1回のk平均法の実行(apply)
57
bigkmeans <- function (x, centers, iter.max = 10, nstart = 1){
(中略)
ans <- foreach(cen = centers, .combine = "choosebest") %dopar% {
require(biganalytics)
(中略)
if (is.null(xdesc)) {
if (mattype == 4) {
res <- .Call("kmeansRIntMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
} else {
res <- .Call("kmeansRNumericMatrix", x, center@address,
clust@address, clustsizes@address, wss@address,
as.integer(iter.max))
}
}
(以降略)
}
並列計算 クラスター中心(split)
1回のk平均法の実行(apply)
結果の集約(combine)
58
4.4.3 bigkmeans関数を用いて計算が速くなる例
UCI Machine Learning RepositoryGisette Data Set http://archive.ics.uci.edu/ml/datasets/Gisette 手書きの数字の「4」と「9」の5000個の特徴に関するデータセット 13,500レコード,5000フィールド
3つのケースについて計算速度を比較する クラスター数:2個 収束までの最大反復回数:50回 クラスタリングの試行回数:10回
k平均法
kmeans関数 bigkmeans関数
データの
読み込み
read.table関数 ① ②
read.big.matrix関数 ③ ―
59
① read.table関数 + kmeans関数> z.rt <- read.table("gisette.data", sep="", header=FALSE)> system.time(z.rt.km <- kmeans(z.rt, centers=2, iter.max=50, + nstart=10, algorithm="MacQueen")) ユーザ システム 経過 413.31 3.18 416.79
② read.table関数 + bigkmeans関数> z.mat <- as.matrix(z.rt)> system.time(z.rt.bkm <- bigkmeans(z.mat, centers=2, iter.max=50, + nstart=10))
ユーザ システム 経過
316.07 0.06 316.46
③ read.big.matrix関数 + bigkmeans関数> z.bm <- read.big.matrix("gisette.data", sep="", header=FALSE, + type="integer")> system.time(z.bm.bkm <- bigkmeans(z.bm, centers=2, iter.max=50,+ nstart=10)) ユーザ システム 経過 131.82 1.01 132.90
60
4.5 biganalyticsパッケージの問題点
bigmemoryパッケージのbig.matrix型は,既存のRのコードでの行列と同様に扱えないため,分析用の関数を自前で作らなければならない.
現状のbiganalyticsパッケージ(Ver.1.0.14)において,分析用の関数として提供されているものは,(一般化)線形回帰,k平均法のみである.
分析 関数名 通常のRの関数
線形回帰 biglm.big.matrix lm
一般化線形回帰 bigglm.big.matrix glm
k平均法 bigkmeans kmeans
61
大規模データの並列(分散)処理といえば・・・
62
大規模データの並列(分散)処理といえば・・・
63
大規模データの並列(分散)処理といえば・・・
Mahoutのような機械学習のアルゴリズムを
biganalyticsパッケージの関数として実装してみよう!
64
今回はナイーブベイズ分類器を実装する.
ナイーブベイズ分類器は,教師あり学習によりクラス分類を行う手法の一つ.
現状ではクラスの予測では並列化を行なっていない(今後,並列化予定).
65
bignaiveBayes <- function(x, ...) UseMethod("bignaiveBayes")
bignaiveBayes.default <-function(x, ccols, summary.cols, laplace = 0, datatype, ...) {
call <- match.call()if (length(summary.cols) != length(datatype))
stop("length(summary.cols) must equal length(datatype)\n") # estimation-function apriori <- bigtable(x, ccols) Yname <- names(apriori)
tables <- lapply(summary.cols, function(i) if (datatype[i] == "char") { tab <- bigtable(x, c(ccols, i)) (tab + laplace) / (rowSums(tab) + laplace * ncol(tab))} else { z <- bigtsummary(x, ccols=ccols, cols=i) z <- sapply(z, function(zz) zz[, c("mean", "sd")])
as.table(t(z))}
) # fix dimname names names(tables) <- colnames(x)[summary.cols] structure(list(apriori = apriori, tables = tables, levels = Yname, call = call), class = "bignaiveBayes")
}
66
predict.bignaiveBayes <- function(object, newdata, type = c("class", "raw"), threshold = 0.001, datatype, ...) {
type <- match.arg(type) attribs <- which(names(object$tables) %in% colnames(newdata)) isnumeric <- datatype!="char" L <- sapply(1:nrow(newdata), function(i) { ndata <- newdata[i,] L <- log(object$apriori) + apply(log(sapply(attribs, function(v) { nd <- ndata[v] if(is.na(nd)) rep(1, length(object$apriori)) else { prob <- if (isnumeric[v]) { msd <- object$tables[[v]] msd[,2][msd[,2]==0] <- threshold dnorm(nd, msd[,1], msd[,2]) } else object$tables[[v]][,nd] prob[prob == 0] <- threshold prob } })), 1, sum) if (type == "class") L else { L <- exp(L) L / sum(L) } }) if (type == "class") factor(object$levels[apply(L, 2, which.max)], levels = object$levels) else t(L)}
67
アジェンダ
1. 自己紹介
2.Rの長所と短所
3.Rにおける大規模データ管理
4. bigmemoryパッケージを用いた並列計算
5. まとめ
68
統計解析ツールとして有望なRは大規模なデータを扱うことが得意ではない.
そのため,Rで大規模なデータを管理,分析しようとすると工夫が必要.
bigmemoryパッケージを用いるとディスクを用いてRAMをはるかに超える量のデータを管理でき,また同一計算機上の複数プロセスでオブジェクトを共有できる.
bigmemoryとその兄弟パッケージを用いると大規模データの管理や集計が可能だが,biganalyticsパッケージに入っている分析用の関数はまだまだ少ない.
そこで,機械学習のアルゴリズムを実装しようと試みた(to be coninued).
69
宣伝
「Rパッケージガイドブック」(4月8日発売)
70
参考文献
Bigmemory Project
Michael J. Kane and John W. Emerso(2010):
The Bigmemory project, http://cran.rproject.org/web/packages/bigmemory/vignettes/Overview.pdf.
Michael J. Kane and John W. Emerso(2010):
Scalable strategies for computing with massive data: The Bigmemory project,
http://www.slideshare.net/joshpaulson/big-memory?from=ss_embed.
「Rを使ったハイパフォーマンスコンピューティング入門」,
統計数理研究所公開講座,2011年1月24日.