28

すべてが問題です!ちょっとした最適化を試み、好奇心からボトルネックを突き止めて、次のことを試しました。

t1 <- rnorm(10)
microbenchmark(
  mean(t1),
  sum(t1)/length(t1),
  times = 10000)

その結果、 mean() は「手で」計算するよりも6倍以上遅くなります!

Internal(mean) を呼び出す前の mean() のコードのオーバーヘッドに起因するものですか、それとも遅いのは C コード自体ですか? なんで?正当な理由、つまり適切なユースケースはありますか?

4

2 に答える 2

35

これは、s3 がメソッドを検索し、次に mean.default で必要な引数の解析が行われるためです。(そして平均的な他のコードも)

sumlengthは両方とも原始関数です。高速になります(ただし、NA値をどのように処理していますか?)

t1 <- rnorm(10)
microbenchmark(
  mean(t1),
  sum(t1)/length(t1),
  mean.default(t1),
  .Internal(mean(t1)),
  times = 10000)

Unit: nanoseconds
                expr   min    lq median    uq     max neval
            mean(t1) 10266 10951  11293 11635 1470714 10000
  sum(t1)/length(t1)   684  1027   1369  1711  104367 10000
    mean.default(t1)  2053  2396   2738  2739 1167195 10000
 .Internal(mean(t1))   342   343    685   685   86574 10000

の内部ビットは/meanよりも高速です。sumlength

詳細については、 http: //rwiki.sciviews.org/doku.php?id=packages:cran:data.table#method_dispatch_takes_time ( mirror ) を参照してください (および を回避する data.table ソリューション.Internal)。

ベクトルの長さを増やすと、プリミティブなアプローチが最速になることに注意してください

t1 <- rnorm(1e7)
microbenchmark(
     mean(t1),
     sum(t1)/length(t1),
     mean.default(t1),
     .Internal(mean(t1)),
+     times = 100)

Unit: milliseconds
                expr      min       lq   median       uq      max neval
            mean(t1) 25.79873 26.39242 26.56608 26.85523 33.36137   100
  sum(t1)/length(t1) 15.02399 15.22948 15.31383 15.43239 19.20824   100
    mean.default(t1) 25.69402 26.21466 26.44683 26.84257 33.62896   100
 .Internal(mean(t1)) 25.70497 26.16247 26.39396 26.63982 35.21054   100

現在、メソッドのディスパッチは、必要な「時間」全体のほんの一部です。

于 2013-09-04T02:28:59.570 に答える
24

meanいくつかの理由により、「手で」計算するよりも遅くなります。

  1. S3メソッドディスパッチ
  2. NA取り扱い
  3. エラー訂正

ポイント1と2はすでにカバーされています。ポイント 3 については、平均を計算するために R が使用するアルゴリズムは?で説明されています。. 基本的に、mean浮動小数点エラーを修正するために、ベクトルを 2 回パスします。sumベクトルを 1 回だけ通過させます。

これらの精度の問題により、であるidentical(sum(t1)/length(t1), mean(t1))可能性があることに注意してください。FALSE

> set.seed(21); t1 <- rnorm(1e7,,21)
> identical(sum(t1)/length(t1), mean(t1))
[1] FALSE
> sum(t1)/length(t1) - mean(t1)
[1] 2.539201e-16
于 2013-09-04T11:35:30.907 に答える