我的代码遇到了性能障碍,我可以在此代码段中重现该问题
rm (z)
z = c()
system.time({z[as.character(1:10^5)] = T})
user system elapsed
48.716 0.023 48.738
我试图预先分配 z
z = logical(10^5)
但这没什么区别。
然后我预先分配了名称
names(z) = character(10^5)
仍然没有速度差异。
system.time({z[as.character(1:10^5)] = T})
user system elapsed
50.345 0.035 50.381
如果我重复测试,无论是否进行预分配,速度都会恢复到合理水平(快 100 倍以上)。
system.time({z[as.character(1:10^5)] = T})
user system elapsed
0.037 0.001 0.039
最后我找到了一个不太好的解决方法:
names(z) = as.character(1:10^5)
system.time({z[as.character(1:10^5)] = T})
user system elapsed
0.035 0.001 0.035
要回到缓慢的时间,您可以 rm(z) 并以不同的方式初始化它,但即使将名称改回其他名称也会使时间变回缓慢。
我是说这不是一个很好的解决方法,因为我不明白它为什么有效,所以很难概括到我事先不知道名称的实际用例。当然,考虑到两个数量级的差异,有人怀疑涉及一些非矢量化或解释器繁重的操作,但您可以看到我的代码是无循环的,并且没有调用我能想到的任何解释代码。然后尝试使用较小的向量,我发现执行时间的增长速度比线性增长快得多,可能是二次的,这指向其他东西。问题是这种速度行为的原因是什么以及使它更快的解决方案是什么。
平台是带有 R 15.2 的 OS X mt lion。谢谢
安东尼奥
最佳答案
我可以推测发生了什么,因为下面的时间似乎符合我的假设。
以下是三个相关的运行:
# run 1 - slow
rm (z)
n <- 3*10^4
z <- vector("logical", n)
system.time({
z[as.character(1:n)] <- T
})
# user system elapsed
# 5.08 0.00 5.10
# run 2 - fast
rm (z)
n <- 3*10^4
z <- vector("logical", n)
system.time({
names(z) <- as.character(1:n)
z[as.character(1:n)] <- T
})
# user system elapsed
# 0.03 0.00 0.03
# run 3 - slow again
rm (z)
n <- 3*10^4
z <- vector("logical", n)
system.time({
for (i in 1:n) names(z)[i] <- as.character(i)
z[as.character(1:n)] <- T
})
# user system elapsed
# 6.10 0.00 6.09
运行 #3 是我认为在后台发生的事情,或者至少是这样的事情:在按名称进行分配时,R 一次查找一个名称,如果没有找到,则在最后分配它名称向量。一次做这件事就是杀死它...
您还指出按以下方式预先分配名称
names(z) <- character(1:n)
没有帮助。呵呵,看到了character(1:n)
返回 ""
所以它没有像你想象的那样设置名称。毫不奇怪,它没有多大帮助。您打算使用 as.character
而不是 character
.最后,您问有什么解决方案可以加快速度?我会说你已经找到了一个(运行#2)。你也可以这样做:
keys <- as.character(1:n)
values <- rep(T, n)
z <- setNames(values, keys)
关于performance - 在 R 中未命名(变为命名)时对向量的分配非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16615401/