裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

for ループが遅いなんて,誰が言った? その3

2012年02月28日 | ブログラミング

わたしは,R には何の義理もないので,好き勝手言います...

> ベンチマークで利用しているデータは10,000行1,000列のデータフレームですが、for 文が有利なように恣意的に設定されている気がします。
> colMeans のボトルネックは as.matrix であり、for 文のボトルネックは R 側で行われる繰り返し処理そのものです。
> よって、同じデータサイズであっても1,000行10,000列のデータフレームであれば for 文が極端に遅くなります。

恣意的に選んだつもりはないし,普通,データ行列というのは,行数は列数より多いもの(統計データはそんな風です)。

最初に,システムの記述。
=====================================================================
Mac OS X
バージョン 10.7.3
プロセッサ 2.4 GHz Intel Core 2 Duo
メモリ 4 GB 667 MHz DDR2 SDRAM  要するに,非力なノートパソコンです(泣)
=====================================================================
> sessionInfo()
R version 2.14.1 RC (2011-12-21 r57955)
Platform: x86_64-apple-darwin9.8.0/x86_64 (64-bit)

locale:
[1] ja_JP.UTF-8/ja_JP.UTF-8/ja_JP.UTF-8/C/ja_JP.UTF-8/ja_JP.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods 
[7] base    
=====================================================================

> よって、同じデータサイズであっても1,000行10,000列のデータフレームであれば for 文が極端に遅くなります。

確かに,1,000 行 10,000 列のデータフレームだと,次のようになりますね。

> gc(); gc()
         used (Mb) gc trigger (Mb) max used (Mb)
Ncells 340340 18.2     407500 21.8   350000 18.7
Vcells 455195  3.5     905753  7.0   879046  6.8
         used (Mb) gc trigger (Mb) max used (Mb)
Ncells 340297 18.2     467875   25   350000 18.7
Vcells 455104  3.5     905753    7   879046  6.8
> set.seed(123454321)
> nr <- 1000
> nc <- 10000
> x <- matrix(rnorm(nr*nc), nr, nc)
> d <- as.data.frame(x)
> gc(); gc(); system.time({
           used  (Mb) gc trigger  (Mb) max used  (Mb)
Ncells   360991  19.3     667722  35.7   420021  22.5
Vcells 20486276 156.3   30561555 233.2 30560771 233.2
           used  (Mb) gc trigger  (Mb) max used  (Mb)
Ncells   360998  19.3     667722  35.7   420021  22.5
Vcells 20486303 156.3   30561555 233.2 30560771 233.2
+     m1 <- numeric(nc)
+     for (i in 1:nc) {
+         m1[i] <- mean(d[, i])
+     }
+ })
   ユーザ   システム       経過 
     1.120      0.123      1.253
> gc(); gc(); system.time({
           used  (Mb) gc trigger  (Mb) max used  (Mb)
Ncells   362956  19.4     667722  35.7   667722  35.7
Vcells 20502981 156.5   30561555 233.2 30560771 233.2
           used  (Mb) gc trigger  (Mb) max used  (Mb)
Ncells   362954  19.4     667722  35.7   667722  35.7
Vcells 20502987 156.5   30561555 233.2 30560771 233.2
+     m3 <- colMeans(d)
+ })
   ユーザ   システム       経過 
     0.612      0.095      0.700             # ★★ 仰るとおり,colMeans が倍くらい速い(パチパチ)
                                                       # ★★ しかし「極端に遅くなる」わけではない

=====================================================================

でも,これは普通の統計データの状況とはちょっと違うので,せめて,行数は列数と同じにしましょうよ。
ということで,10,000 行 10,000 列のデータフレームで,やってみましょう。

> gc(); gc()
           used  (Mb) gc trigger  (Mb) max used  (Mb)
Ncells   363975  19.5     667722  35.7   667722  35.7
Vcells 20524784 156.6   45054625 343.8 40571168 309.6
           used  (Mb) gc trigger  (Mb) max used  (Mb)
Ncells   363973  19.5     667722  35.7   667722  35.7
Vcells 20524790 156.6   45054625 343.8 40571168 309.6
> set.seed(123454321)
> nr <- 10000 ★★ 行数を 10 倍にしました(^_^;)
> nc <- 10000
> x <- matrix(rnorm(nr*nc), nr, nc)
> d <- as.data.frame(x)
> gc(); gc(); system.time({
            used   (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells    363966   19.5     667722   35.7    667722   35.7
Vcells 200524763 1529.9  312110644 2381.3 312104760 2381.2
            used   (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells    363973   19.5     667722   35.7    667722   35.7
Vcells 200524790 1529.9  312110644 2381.3 312104760 2381.2
+     m1 <- numeric(nc)
+     for (i in 1:nc) {
+         m1[i] <- mean(d[, i])
+     }
+ })
   ユーザ   システム       経過 
     1.402      0.040      1.451 # ★★ for は,原理的に言ってそう増えるわけではない。
> gc(); gc(); system.time({
            used   (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells    363975   19.5     667722   35.7    667722   35.7
Vcells 200527435 1530.0  312110644 2381.3 312104760 2381.2
            used   (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells    363973   19.5     667722   35.7    667722   35.7
Vcells 200527441 1530.0  312110644 2381.3 312104760 2381.2
+     m3 <- colMeans(d)
+ })
   ユーザ   システム       経過 
     3.975     15.272    191.106 # ★★ オオッ。これはなんだ。時間は倍以上掛かるし,システムは 15 秒だって?
                                 # これ以上行数を増やして実験するなんて,もうイヤだ(^_^)

>  データフレームを行列にしてから計算するのだから遅くてもしょうがないじゃあないか(怒)

それはそうだけど,前にも言ったけど,データフレームについて計算しようというのなら行列に変換するのに必要な時間も勘定されてもしょうがないでしょう。それがいやなら,前にも言ったけど,前もって行列にしておくこと。行列のときに colMeans は速いっていうのは否定していないのだから。怒りの矛先を私に向けられても,戸惑うばかり...

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PVアクセスランキング にほんブログ村

PVアクセスランキング にほんブログ村