たとえば、結果を取得するために必要な反復回数がわからない場合など、ループを使用する必要がある場合があります。例として、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を実行できます。しかし、私はあなたのユースケースを誤解しているかもしれません