For 循环的最优构造
为了说明 good for loop 构造的效果,我们将以四种不同的方式计算每列的平均值:
- 使用优化不佳的 for 循环
- 使用优化的 for 循环
- 使用
*apply
系列功能 - 使用
colMeans
功能
这些选项中的每一个都将以代码显示; 将显示执行每个选项的计算时间的比较; 最后将讨论差异。
环路优化不佳
column_mean_poor <- NULL
for (i in 1:length(mtcars)){
column_mean_poor[i] <- mean(mtcars[[i]])
}
针对循环进行了优化
column_mean_optimal <- vector("numeric", length(mtcars))
for (i in seq_along(mtcars)){
column_mean_optimal <- mean(mtcars[[i]])
}
vapply
功能
column_mean_vapply <- vapply(mtcars, mean, numeric(1))
colMeans
功能
column_mean_colMeans <- colMeans(mtcars)
效率比较
对这四种方法进行基准测试的结果如下所示(代码未显示)
Unit: microseconds
expr min lq mean median uq max neval cld
poor 240.986 262.0820 287.1125 275.8160 307.2485 442.609 100 d
optimal 220.313 237.4455 258.8426 247.0735 280.9130 362.469 100 c
vapply 107.042 109.7320 124.4715 113.4130 132.6695 202.473 100 a
colMeans 155.183 161.6955 180.2067 175.0045 194.2605 259.958 100 b
请注意,优化的 for
循环消除了构造不良的 for 循环。构造不良的 for 循环不断增加输出对象的长度,并且在每次改变长度时,R 重新评估对象的类。
通过在开始循环之前声明输出对象的类型及其长度,优化的 for 循环消除了一些此开销负担。
然而,在这个例子中,vapply
函数的使用使计算效率提高了一倍,主要是因为我们告诉 R 结果必须是数字(如果任何一个结果不是数字,则会返回错误)。
使用 colMeans
功能比 vapply
功能慢。这种差异可归因于在 colMeans
中执行的一些错误检查,主要是由于 vapply
函数中未执行的 as.matrix
转换(因为 mtcars
是 data.frame
)。