A veces tenemos que usar bucles, por ejemplo, cuando no sabemos cuántas iteraciones necesitamos para obtener el resultado. Tome los bucles while como ejemplo. A continuación se detallan los métodos que debe evitar:
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
Estos son muy ineficientes porque R copia el vector cada vez que se agrega.
La forma más eficiente de agregar es usar index. Tenga en cuenta que esta vez lo dejé iterar 1e7 veces, pero aún es mucho más rápido que c
.
a=numeric(0)
system.time(
{
while(length(a)<1e7){
a[length(a)+1]=pi
}
}
)
# user system elapsed
# 5.71 0.39 6.12
Esto es aceptable Y podemos hacerlo un poco más rápido reemplazando [
con [[
.
a=numeric(0)
system.time(
{
while(length(a)<1e7){
a[[length(a)+1]]=pi
}
}
)
# user system elapsed
# 5.29 0.38 5.69
Tal vez ya haya notado que length
puede llevar mucho tiempo. Si reemplazamos length
con un contador:
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
Como mencionaron otros usuarios, la preasignación del vector es muy útil. Pero esto es una compensación entre la velocidad y el uso de la memoria si no sabe cuántos bucles necesita para obtener el resultado.
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
Un método intermedio es agregar gradualmente bloques de resultados.
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
; o podrías hacer vector = vector + valores. Pero podría estar malentendiendo su caso de uso