Cloud2016 你举的这个慢循环例子正是我说的“在循环内部用了不恰当的操作”,“把不该循环的事情用循环做了”。这里 for 循环和 apply 的对比是不公平的,因为后者是用了基于 C 语言的向量化的函数 sum(),当然会比在 R 层面上显式地一步步相加快很多;换句话说,你对比的是 R 层面上的加法和 C 层面上的加法的速度。公平的对比应该是下面这样。你的例子是对列求和,但数据只有1列,对行显式循环没多大意义。我下面对比的是对列循环,循环和 apply 都调用 sum() 求和,鉴于 apply() 的本质是 for 循环加上一些额外的操作,它一定不会比循环快。
N = 10 # 列数
A = matrix(rnorm(1e7),nrow = 1e7, ncol = N)
system.time({
s1 = numeric(N)
for (i in seq_len(N)) {
s1[i] = sum(A[, i])
}
}) # 1.090 秒
system.time({
s2 = apply(A, 2, sum)
}) # 1.851 秒
all(s1 == s2) # TRUE
当然,这个测速方法也是不科学的,要测速还是得上 microbenchmark,免得受一些其它因素影响(如垃圾回收)。
N = 10
A = matrix(rnorm(1e6),nrow = 1e6, ncol = N)
sum_for = function() {
s1 = numeric(N)
for (i in seq_len(N)) {
s1[i] = sum(A[, i])
}
s1
}
sum_apply = function() {
apply(A, 2, sum)
}
microbenchmark::microbenchmark(sum_for(), sum_apply())
Unit: milliseconds
expr min lq mean median uq max neval
sum_for() 96.01921 116.7481 133.9847 119.2918 126.4609 367.2931 100
sum_apply() 172.35825 191.8426 234.0205 198.7329 237.6927 501.4662 100