裏 RjpWiki

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

9年経ったが,R の「for ループが遅いなんて,誰が言った?」はどうなった?

2021年07月26日 | ブログラミング

for ループが遅いなんて,誰が言った?
https://blog.goo.ne.jp/r-de-r/e/49dd48ded7e3605578bbcde95731e412
https://blog.goo.ne.jp/r-de-r/e/4515f9867b017eed1a97cdb8173d8cdc
https://blog.goo.ne.jp/r-de-r/e/1a760a8bee2e3dfb57ffd9235294d4bd
https://blog.goo.ne.jp/r-de-r/e/e1ced6d1474bb9da6a1cf089c15da319
は,2012年の2月末の記事である。
10000×1000のデータフレームでは,forループ≒sapply > colMeans > apply
それを行列に変換したものでは,colMeans > forループ > apply

その後 2018年の3月末に,同じ趣旨で別の人が記事を書いた。

data.frameの高速演算には列ごとならlapply、行ごとならReduceを使おう
https://qiita.com/Atsushi776/items/176426e2195b18eb65b4
行列の場合もデータフレームの場合も,速度は,行列用の関数 > apply > for
データフレームの場合は,lapply が群を抜いて速い。sapply は lapply の結果を simplify するので,ちょっとだけ余分な時間が掛かる。

後者の場合(列ごとの演算の場合)に for は遅いとしているが,

Rのforは遅いと誰が言った? (data.frameの高速演算には列ごとならlapply、行ごとならReduceを使おうの補足)
https://qiita.com/Atsushi776/items/c31f2345b9c698354c81
行ごとの場合で,100行100,000列 の場合は reduce を使う場合より for ループの方が速い。
ということで,for も場合により速いということ。

その後3年も経って,R も進化したかどうか,どうなっているかをやってみた。
列ごとの集計についてのみ。

> sessionInfo()
R version 4.0.5 Patched (2021-03-31 r80136)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.7

nr = 5000
nc = 100
set.seed(777)
x = matrix(rnorm(nr*nc), nr, nc)
d = as.data.frame(x)

library(microbenchmark)
cpu = microbenchmark(
    lapply.df = lapply(d, sum),
    sapply.df = sapply(d, sum),
    for.loop.df = {
        m1 = numeric(nc)
        for (i in 1:nc) {
            m1[i] = sum(d[,i])
        }
        m1
    },
    colSums.df = colSums(d),
    apply.df = apply(d, 2, sum),
    colSums.mat = colSums(x),
    for.loop.mat = {
        M1 = numeric(nc)
        for (i in 1:nc) {
            M1[i] = sum(x[,i])
        }
        M1
    },
    apply.mat = apply(x, 2, sum),
    unit="ms"
 )

par(mar=c(2.7, 5.8, 0.5, 0.5), mgp=c(1.0, 0.5, 0), tcl=-0.2)
plot(cpu,
 col=rep(c("blue", "red"), c(5, 3)),
    las=1, horizontal=TRUE, log = "x",
    xlab="", ylab=""
)
mtext("cpu time in milliseconds", 1, 1.5)

実行結果

1. 小規模なデータセット

nr = 5000
nc = 100

Unit: milliseconds
         expr       min        lq       mean     median         uq       max neval   cld
    lapply.df  1.047031  1.081145  1.1332266  1.1010855  1.1366530  1.768589   100 a    
    sapply.df  1.074273  1.108415  1.1708123  1.1437340  1.1752400  1.874276   100 a    
  for.loop.df  4.970888  5.328881  6.8997624  5.4409915  5.5839455 65.615935   100   c  
   colSums.df  3.362236  3.518504  3.7168504  3.5814160  3.6827735  9.154761   100  b   
     apply.df 10.747753 12.295381 12.7935086 12.4636335 12.7963960 16.218739   100     e
  colSums.mat  0.420709  0.438020  0.4669311  0.4453005  0.4666935  0.740547   100 a    
 for.loop.mat  7.191930  7.561473  8.6612821  7.7115335  8.0154290 48.668296   100    d 
    apply.mat  7.518857  9.143223  9.4147229  9.3349020  9.5605895 12.260340   100    d 

所見

データフレームの場合は,lapply, sapply が速く,apply は一番遅い。
colSums は以外と遅い。
for loop を使う場合は,colSums より遅い。

行列の場合は,colSums がダントツで速い。
for loop は遅いが,apply よりは速い。

2. 大規模なデータセット

nr = 50000
nc = 1000

Unit: milliseconds
         expr        min        lq       mean     median        uq       max neval   cld
    lapply.df  109.28227  154.7461  238.27326  226.45196  294.1781  606.8323   100 a    
    sapply.df  109.75268  150.9724  223.23908  207.86459  276.3348  641.9150   100 a    
  for.loop.df  126.39996  186.2769  271.16484  245.08860  338.0778 1575.5968   100 a    
   colSums.df  306.50184  440.1110  661.95370  585.96930  825.0703 1725.2760   100  b   
     apply.df 1262.78601 1791.5473 2603.76553 2430.82437 3461.5491 7413.4465   100     e
  colSums.mat   43.77521   64.4854   89.69947   85.70177  108.2785  215.9835   100 a    
 for.loop.mat  464.34522  718.2325 1059.18931  894.83492 1333.1409 3511.8967   100   c  
    apply.mat  960.38814 1426.7567 2049.73518 1778.87375 2604.3161 5885.0181   100    d 

所見

データフレームの場合は,lapply, sapply, for loop が同じくらい速く,apply は一番遅い。
colSums は以外と遅い。

行列の場合は,colSums がダントツで速い。
for loop は遅いが,apply よりは速い。

結論

for はそんなに遅くない。

コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« 根拠なき自信 | トップ | 行列あるいはデータフレーム... »
最新の画像もっと見る

コメントを投稿

ブログラミング」カテゴリの最新記事