Movatterモバイル変換


[0]ホーム

URL:


あらびき日記

一部のデータフレームにおいてfor ループがcolMeansより速い理由

()

先日、タイムラインを眺めていたらこんなエントリーが出てきました。
for ループが遅いなんて,誰が言った? - 裏 RjpWiki

「データフレームの場合は colMeans より for 文の方が速い」という奇をてらうような内容です。
どうしてそうなるかについて全く解説されておらず、限定的な話なのにあたかも普遍的な事実であるかのような書き方がされています。
間違った認識が広まってしまうとよろしくないのでちゃんと検証しました。

そもそもデータフレームだとどうして遅くなるか?

colMeans の一番最初に次のような処理があります。

if(is.data.frame(x))x<-as.matrix(x)

つまり、一番最初に行列に変換するので、後の処理は行列の場合と全く同じということです。
よって、行列に変換するところがボトルネックになっていることは明らかです。

実際、次の方法で確認することができます。

>nr<-10000>nc<-1000>set.seed(1)>d<-as.data.frame(matrix(rnorm(nr*nc),nr,nc))>Rprof(interval=0.001);invisible(colMeans(d));Rprof(NULL)>summaryRprof()$by.selfself.timeself.pcttotal.timetotal.pct"as.matrix.data.frame"0.06679.520.08197.59"unlist"0.01315.660.01315.66"levels"0.0022.410.0022.41"colMeans"0.0011.200.083100.00"as.matrix"0.0011.200.08298.80$by.totaltotal.timetotal.pctself.timeself.pct"colMeans"0.083100.000.0011.20"as.matrix"0.08298.800.0011.20"as.matrix.data.frame"0.08197.590.06679.52"unlist"0.01315.660.01315.66"levels"0.0022.410.0022.41$sample.interval[1]0.001$sampling.time[1]0.083

この結果から、先ほどのエントリーと同じ形式のデータだと as.matrix の部分で colMeans 全体の処理時間のうち約99%を占めていることがわかります。

再検証

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

>library(rbenchmark)>nr<-10000>nc<-1000>set.seed(1)>d<-as.data.frame(matrix(rnorm(nr*nc),nr,nc))># 10,000行1,000列だと for 文の方が遅い>benchmark({+m1<-numeric(nc)+for(iin1:nc){+m1[i]<-mean(d[,i])+}+},+colMeans(d))testreplicationselapsedrelativeuser.selfsys.selfuser.child1{1008.7781.0000008.7370.02802colMeans(d)10020.7652.36557316.5624.1730sys.child1020># 1,000行10,000列だと colMeans の方が速い>d2<-as.data.frame(t(d))>benchmark({+m2<-numeric(nr)+for(iin1:nr){+m2[i]<-mean(d2[,i])+}+},+colMeans(d2))testreplicationselapsedrelativeuser.selfsys.selfuser.child1{100105.2013.116697100.5744.45102colMeans(d2)10033.7541.00000029.4154.2830sys.child1020

列数が10倍になると for 文の処理時間も約10倍になっていることがわかるかと思います。10,000個の値に対して平均を取るのも1,000個の値に対して平均を取るのも処理時間的には大差ないので、繰り返し回数が増えた分だけ遅くなっているわけです。

結論

以上をまとめると

  • データサイズが大きいデータフレームは as.matrix がボトルネックになる
  • for 文は繰り返し回数に比例して遅くなる
  • colMeans が速いか for 文が速いかはケースバイケース

と言えます。個人的には for 文の方が速いかどうかなんて気にせず一貫して colMeans を使えば良いのではないかと思います。

ちなみに今回検証に使ったマシンのスペックは次のとおりです。

  • OS: Mac OS X 10.6.8
  • CPU: 2.4 GHz Intel Core i5
  • R: 2.14.1

最近のエントリー

人気エントリー

プロフィール

広告

SRE・データエンジニア募集中!

タグ一覧

アーカイブ


[8]ページ先頭

©2009-2025 Movatter.jp