问题就在这里!我只是尝试进行了一些优化,找到了瓶颈所在。出于好奇,我尝试了这个:
t1 <- rnorm(10)
microbenchmark(
mean(t1),
sum(t1)/length(t1),
times = 10000)
结果表明,使用mean()函数要比手动计算慢6倍以上!
这是由于mean()函数在调用Internal(mean)之前的代码开销较高还是C代码本身较慢引起的?为什么?有没有好的理由和使用场景?
问题就在这里!我只是尝试进行了一些优化,找到了瓶颈所在。出于好奇,我尝试了这个:
t1 <- rnorm(10)
microbenchmark(
mean(t1),
sum(t1)/length(t1),
times = 10000)
结果表明,使用mean()函数要比手动计算慢6倍以上!
这是由于mean()函数在调用Internal(mean)之前的代码开销较高还是C代码本身较慢引起的?为什么?有没有好的理由和使用场景?
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(备份)了解更多细节(以及避免使用 .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)
比其他所有方法都快? - Josh O'Brienbase::mean
在向量上执行两次遍历(在 C 语言级别),以校正数值精度问题(请参见 src/summary.c)。顺便说一句,data.table 优化的均值也这样做,以保留这个好用的特性并且与基本的均值函数完全相同。sum
是单次遍历,而 length
存储在向量头部(没有循环)中。 - Matt Dowlemean
的速度比手动计算要慢,原因有以下几点:
NA
处理前两点已经解释过了。第三点在这里有讨论,基本上是为了校正浮点误差,mean
需要对向量进行两次遍历,而 sum
只需要一次。
请注意,由于这些精度问题,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
rowMeans
和colMeans
? - Ferdinand.kraftrowMeans
和colMeans
不进行任何错误校正。 - Joshua Ulrich