有时,例如,当我们不知道需要多少次迭代才能获得结果时,就不得不使用循环。以while循环为例。以下是您绝对应避免的方法:
a=numeric(0)
b=1
system.time(
{
while(b<=1e5){
b=b+1
a<-c(a,pi)
}
}
)
# user system elapsed
# 13.2 0.0 13.2
a=numeric(0)
b=1
system.time(
{
while(b<=1e5){
b=b+1
a<-append(a,pi)
}
}
)
# user system elapsed
# 11.06 5.72 16.84
这些效率非常低,因为R每次附加向量时都会复制该向量。
附加的最有效方法是使用索引。请注意,这次我让其迭代1e7次,但仍比快得多c
。
a=numeric(0)
system.time(
{
while(length(a)<1e7){
a[length(a)+1]=pi
}
}
)
# user system elapsed
# 5.71 0.39 6.12
这是可以接受的。而我们可以通过替换[
为来使其更快一些[[
。
a=numeric(0)
system.time(
{
while(length(a)<1e7){
a[[length(a)+1]]=pi
}
}
)
# user system elapsed
# 5.29 0.38 5.69
也许您已经注意到这length
可能很耗时。如果我们length
用一个计数器代替:
a=numeric(0)
b=1
system.time(
{
while(b<=1e7){
a[[b]]=pi
b=b+1
}
}
)
# user system elapsed
# 3.35 0.41 3.76
正如其他用户提到的那样,预先分配向量非常有帮助。但这是在速度和内存使用之间的权衡,如果您不知道要获得结果需要多少个循环。
a=rep(NaN,2*1e7)
b=1
system.time(
{
while(b<=1e7){
a[[b]]=pi
b=b+1
}
a=a[!is.na(a)]
}
)
# user system elapsed
# 1.57 0.06 1.63
一种中间方法是逐渐添加结果块。
a=numeric(0)
b=0
step_count=0
step=1e6
system.time(
{
repeat{
a_step=rep(NaN,step)
for(i in seq_len(step)){
b=b+1
a_step[[i]]=pi
if(b>=1e7){
a_step=a_step[1:i]
break
}
}
a[(step_count*step+1):b]=a_step
if(b>=1e7) break
step_count=step_count+1
}
}
)
#user system elapsed
#1.71 0.17 1.89
vector = values
; 或者您可以执行vector = vector + values。但是我可能会误解您的用例