在R
中,我如何清晰地比较相同问题的不同解决方案,并在每个解决方案之间保持"公平"?在其他解决方案之前运行消耗资源的解决方案是否会改变后一个解决方案的性能?如何在每次测试之间"清理"机器的状态?
假设我想计算一个矩阵列的均值,我可以用简单的或复杂的方法来做:
set.seed(9)
N = 1e7
ncol = 1e3
myT = matrix(runif(N), ncol = ncol)
func1 <- function(mat) {
colMeans(mat)
}
func2 <- function(mat) {
apply(mat, 2, function(x) sum(x)/length(x))
}
func3 <- function(mat) {
nrows = c()
for (i in 1:nrow(mat)) {
nrows = c(nrows, 1) # yes, this is very stupid ;-)
}
colSums(mat) / sum(nrows)
}
system.time( replicate(1, t1 <- func1(myT)))
# user system elapsed
# 0.012 0.000 0.011
system.time( replicate(1, t2 <- func2(myT)))
# user system elapsed
# 0.136 0.036 0.170
system.time( replicate(1, t3 <- func3(myT)))
# user system elapsed
# 0.140 0.032 0.170
对于同一个测试,多次运行system.time()
会得到不同的结果(可能会改变结论)。我注意到对于更复杂、消耗资源的解决方案尤其如此,而最干净的解决方案往往具有更一致的执行时间——这是什么原因呢?如何避免同一表达式执行之间的大变化,以及如何防止它们相互干扰?
在测试之间调用gc()
是否有用,是否足够?
我也知道microbenchmark
包,但我正在寻找更多的"手动",以了解发生了什么。
我正在使用RStudio
,以防万一…
microbenchmark
就是为此而设计的。system.time()
没有那么详细
set.seed(9)
N = 1e5
ncol = 1e3
myT = matrix(runif(N), ncol = ncol)
library(microbenchmark)
microbenchmark(
colmeans = colMeans(myT),
wrong_apply = apply(myT, 2, function(x) sum(x)/length(x)), # wrong in case of NA
correct_apply = apply(myT, 2, mean, na.rm = TRUE), # correct in case of NA
stupid = {
nrows = c()
for (i in 1:nrow(myT)) {
nrows = c(nrows, 1) # yes, this is very stupid ;-)
}
colSums(myT) / sum(nrows)
}
)
输出Unit: microseconds
expr min lq mean median uq max neval cld
colmeans 87.235 92.367 96.44175 95.787 98.781 129.142 100 a
wrong_apply 3004.886 3071.595 3483.02090 3166.739 3267.445 18707.947 100 b
correct_apply 7595.387 7895.148 8850.87886 8106.179 8461.745 13928.438 100 c
stupid 144.109 156.510 166.15237 163.351 171.690 255.290 100 a