Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
による高速処理
DATE: 2016/11/18 AUTHOR: Atsushi Yoshida
~ まだfor使ってるの? ~
自己紹介
吉田 敦(よしだ あつし)
• 鎌倉研究室M2
• 趣味:R
–Rでデータサイエンス以外のことをするのが
好き
– 前処理が一番楽しい
2
テーマ
3
遅い遅いと謳われるRだけど、
頑張って高速に処理しようぜって話
高速化のためのよくあるTips
• forループよりもapplyファミリー
• ループ演算よりもベクトル演算
• オブジェクトは何度も変形しない
• 内部関数や著名なパッケージを使う
• 行列計算用ライブラリを使う
• 並列化する
• そもそもRで書かない
4
高速化のためのよくあるTips
1. ループ演算よりもベクトル・行列演算
2. 著名なパッケージや内部関数を使う
3. ループ演算は並列化する
5
高速化のためのよくあるTips
1. ループ演算よりもベクトル・行列演算
 『forを使うな 第一弾』(初級者向け)
2. 著名なパッケージや内部関数を使う
 『覚えゲー』(中級者向け)
3. ループ演算は並列化する
 『ハイスペマシンにあやかる』
『forを使うな 第二弾』(初・上級者向け)
6
7
『forを使うな』 第一弾
ループ演算よりもベクトル・行列演算
Rは,ベクトル演算が得意
『ループ演算よりもベクトル・行列演算』とは
8
vec <- seq1 + seq2
例えば、こういうこと
N <- 1000000
vec <- integer(N)
seq1 <- seq2 <- 1:N
for(i in 1:N) {
vec[i] <- seq1[i] + seq2[i]
}
関数を各要素に対して、実行してくれる
『forを使うな』 第一弾
9
system.time({
vec <- seq1 + seq2
})
## user system elapsed
## 0.006 0.000 0.006
N <- 1000000
vec <- integer(N)
seq1 <- seq2 <- 1:N
system.time({
for(i in 1:N) vec[i] <- seq1[i] + seq2[i]
})
## user system elapsed
## 1.749 0.037 1.831
ベクトル化前
ベクトル化後
高速化の例
なぜ出来るか?
⇒ 関数がベクトル演算に対応しているから
10
sqrt(1:3)
## [1] 1.000000 1.414214 1.732051
iconv(c("あ", "い", "う"), to = "shift-jis")
## [1] "x82xa0" "x82xa2" "x82xa4"
できる例
できない例
Nippon::zen2han(c("1", "4", "16"))
## [1] "1416"
Warning message:
In if (Encoding(s) != "UTF-8") s <- iconv(s, from = "", to = "UTF-8") : the
condition has length > 1 and only the first element will be used
余談
• Vectorize関数を使うと、関数を無理やり
ベクトル演算できるように変形できる
11
Vectorize(function)
Vectorize(Nippon::zen2han)(c("1", "4", "16"))
## 1 4 16
## "1" "4" "16"
12
『forを使うな』 第二弾
ループ演算は並列化する
Rは,シングルコアで動いている
並列処理のイメージ
13
通常のR
並列処理
※詳しいことは知りません
処理を渡す 結果を返す
処理を渡す
計算
結果を返す
計算
foreach パッケージ
• Revolution Analytics社が開発
• forと同じような使い方でわかりやすい
• applyファミリのように使い分ける必要なし
• 返り値を返す
• イテレータを使った省メモリループ
• 並列化をサポート
14
forと同じような使い方
15
for文
foreach文
『in』ではなく『 =』
%do% が必要
for(i in 1:10) {
sqrt(i)
}
foreach(i = 1:10) %do% {
sqrt(i)
}
返り値を返す
16
for文
foreach文
各ループの返り値を
まとめて返す
vec <- numeric(150)
for(i in 1:150) {
vec[i] <- sum(iris[i, 1:4])
}
vec <- foreach(i = 1:150) %do% {
sum(iris[i, 1:4])
}
17
18
19
20
並列化の基本
21
22
23
24
バックエンドの管理
• クラスタの作成・登録・停止がめんどい
25
パッケージの使用
• ループ内でパッケージを使用する場合、
全て指定しなければならない
26
27
28
これを超簡単に書くパッケージがある
29
pforeach
30
31
32
33
34
35
引数
36
この2つを覚えるだけで大丈夫
その他引数については下記を参照
URL - R で超簡単に並列処理を書けるpforeach パッケージ
書籍 - 『Rによるハイパフォーマンスコンピューティング』
• .combine
--> 結合関数を与える
• .parallel
--> 並列のオン・オフを指定する
結合の引数 --> .c (.combine)
37
pforeach(i = 1:3, .c = c) (sqrt(i))
## [1] 1.000000 1.414214 1.732051
pforeach(i = 1:3, .c = list) (sqrt(i))
## [[1]]
## [1] 1
##
## [[2]]
## [1] 1.414214
##
## [[3]]
## [1] 1.732051
##
pforeach(i = 1:3, .c = rbind) (sqrt(i))
## [,1]
## result.1 1.000000
## result.2 1.414214
## result.3 1.732051
デフォルトは c 関数
時々使う?
list 関数
割と使いそう
rbind 関数
並列のオン・オフ
38
pforeach(i = 1:3, .parallel = FALSE) (sqrt(i))
## [1] 1.000000 1.414214 1.732051
npforeach(i = 1:3) (sqrt(i))
## [1] 1.000000 1.414214 1.732051
方法① .parallel = FALSEを付ける
方法② pforeachではなくnpforeachを使う
非並列
非並列
pforeachはデフォルトで並列化
デバック時など,非並列化したいときがある
pforeach(i = 1:3) (sqrt(i))
## [1] 1.000000 1.414214 1.732051
39
40
41
例: ランダムフォレストの並列化
42
library(foreach)
library(kernlab)
library(randomForest)
library(doParallel)
data(spam)
cores <- detectCores()
cl <- makePSOCKcluster(cores)
registerDoParallel(cl)
fit.rf <- foreach(ntree = rep(250, cores),
.combine = combine,
.export = "spam",
.packages = "randomForest") %dopar% {
randomForest(type ~ ., data = spam, ntree = ntree)
}
stopCluster(cl)
foreach
例: ランダムフォレストの並列化
43
library(pforeach)
library(kernlab)
library(randomForest)
data(spam)
fit.rf <- pforeach(ntree = rep(250, .cores),
.c = combine) ({
randomForest(type ~ ., data = spam, ntree = ntree)
})
pforeach
すっきりしました!!
参考
• URL
– for を捨てよ、foreach を書こう
– R で超簡単に並列処理を書けるpforeach パッケージ
– R で超簡単に並列処理を書けるパッケージ pforeach
を作った - ほくそ笑む
– foreachについてまとめたい - J's blog
– foreachでprogressbarを表示する - J's blog
• 書籍
– 『Rによるハイパフォーマンスコンピューティング』
44
progress barを出す(1)
45
まずはこの関数を
読み込みます
参考: foreachでprogressbarを表示する - J's blog
progress barを出す(2)
46
そして、ここに
繰り返し数(N)と
結合関数(デフォルトはc)を
入れると・・・?
progress barが表示できました!!
参考: foreachでprogressbarを表示する - J's blog
今日のまとめ
47
一歩上のR使いになるために
⇒『forを捨てよ、pforeachを書こう』
Enjoy!!
余談
• 並列対応のR
– pqR(ただし2系のRのみ)
– Microsoft R
• 高速化ライブラリ
– OpenBLAS(BLASという数値計算ライブラリ)
– Intel MKL(並列化可能な数値計算ライブラリ)
• Rcpp
– 参考
(https://www.gitbook.com/book/teuder/introducti
on-to-rcpp/details/ja)
49

More Related Content

Rによる高速処理 まだfor使ってるの?

Editor's Notes

  1. #### library(dplyr) cl <- makeCluster(3) registerDoParallel(cl) foreach(i = 1:150, .packages = "dplyr") %dopar% { iris[i, ] %>% select(-Species) %>% sum } stopCluster(cl) #### square <- function(x) x**2 execute <- function() { cl <- makeCluster(3) registerDoParallel(cl) foreach(i = 1:150, .export = "square") %dopar% { square(i) } stopCluster(cl) } execute() #### library(foreach) library(doParallel) cl <- makeCluster(3) registerDoParallel(cl) foreach(i = 1:3) %dopar% { sqrt(i) } stopCluster(cl) #### library(pforeach) pforeach(i=1:3) ({ sqrt(i) }) #### pforeach(i = 1:3, .c = c) (sqrt(i)) pforeach(i = 1:3, .c = list) (sqrt(i)) pforeach(i = 1:3, .c = rbind) (sqrt(i)) #### pforeach(i = 1:3) (sqrt(i)) pforeach(i = 1:3, .parallel = FALSE) (sqrt(i)) npforeach(i = 1:3) (sqrt(i)) #### pforeach(i=1:3, .cores = 2) ({ i ** 2 }) #### pforeach(i=1:3, .seed = 71) ({ i ** 2 }) #### library(foreach) library(kernlab) library(randomForest) library(doParallel) data(spam) cores <- detectCores() cl <- makePSOCKcluster(cores) registerDoParallel(cl) fit.rf <- foreach(ntree = rep(250, cores), .combine = combine, .export = "spam", .packages = "randomForest") %dopar% { randomForest(type ~ ., data = spam, ntree = ntree) } stopCluster(cl) #### library(pforeach) library(kernlab) library(randomForest) data(spam) fit.rf <- pforeach(ntree = rep(250, .cores), .c = combine) ({ randomForest(type ~ ., data = spam, ntree = ntree) }) #### pb <- function(N, FUN = c) { pbar <- txtProgressBar(min = 2, max = N, style = 3) count <- 0L if(is.character(FUN)) { FUN <- get(FUN) } function(...) { count <<- count + length(list(...)) - 1L setTxtProgressBar(pbar, count) if(count == (N-1)) { cat("\n") } FUN(...) } } #### N <- 10000 pforeach(i = 1:N, .combine = pb(N), .multicombine = TRUE) ({ sqrt(i) })[1:10]