【问题标题】:Why is mean() so slow?为什么 mean() 这么慢?
【发布时间】:2013-09-07 09:41:18
【问题描述】:

一切都在问题中!我只是尝试做一些优化,并确定瓶颈,出于好奇,我尝试了:

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

结果是 mean() 比“手动”计算慢 6 倍以上!

它是源于调用 Internal(mean) 之前 mean() 代码中的开销,还是 C 代码本身较慢?为什么?是否有充分的理由和良好的用例?

【问题讨论】:

标签: r performance optimization


【解决方案1】:

这是由于 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 的内部位甚至比sum/length 还要快。

请参阅http://rwiki.sciviews.org/doku.php?id=packages:cran:data.table#method_dispatch_takes_time (mirror) 了解更多详情(以及避免.Internal 的 data.table 解决方案)。

注意,如果我们增加向量的长度,那么原始方法是最快的

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

现在方法分派只是所需总“时间”的一小部分。

【讨论】:

  • 基准如何根据不同长度的输入向量进行缩放?
  • 有没有想过为什么(使用长向量)sum(t1)/length(t2) 比所有其他人都快?
  • @JoshO'Brien base::mean 两次遍历向量(在 C 级别)以校正数值精度(参见 src/summary.c)。顺便说一句,data.table 优化的均值也这样做是为了保留这个不错的特性并与基本均值完全相同。 sum 是单次传递,length 在向量的标头中(无循环)。
  • @MatthewDowle -- 谢谢!我还没有写过任何 C,但看起来第二个循环的作用是 +/- 以确保您对 10000000.1 - 10000000.2 范围内的数字向量获得与 0.1 - 范围内的向量相同的精度0.2(直到在第一种情况下最终截断结果)。对吗?
  • @JoshO'Brien:查看我的答案和链接的问题。
【解决方案2】:

mean 比“手动”计算慢有几个原因:

  1. S3 方法调度
  2. NA处理
  3. 纠错

第 1 点和第 2 点已涵盖。第 3 点在What algorithm is R using to calculate mean? 中讨论。基本上,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

【讨论】:

  • 这是否也适用于rowMeanscolMeans
  • @Ferdinand.kraft:我不确定“this”指的是什么,所以我无法回答“是”或“否”... :) 但是 rowMeans 和 @987654332 @ 不做任何错误更正。
猜你喜欢
  • 2021-09-03
  • 2016-09-28
  • 2020-02-08
  • 2012-07-17
  • 2011-11-07
  • 2015-08-24
  • 2013-08-06
  • 2014-07-16
  • 2011-01-02
相关资源
最近更新 更多