A volte dobbiamo usare i loop, ad esempio, quando non sappiamo quante iterazioni abbiamo bisogno per ottenere il risultato. Prendi ad esempio i loop. Di seguito sono riportati i metodi che dovresti assolutamente evitare:
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
Questi sono molto inefficienti perché R copia il vettore ogni volta che viene aggiunto.
Il modo più efficiente di aggiungere è utilizzare l'indice. Nota che questa volta l'ho lasciato iterare 1e7 volte, ma è comunque molto più veloce di c
.
a=numeric(0)
system.time(
{
while(length(a)<1e7){
a[length(a)+1]=pi
}
}
)
# user system elapsed
# 5.71 0.39 6.12
Questo è accettabile E possiamo renderlo un po 'più veloce sostituendolo [
con [[
.
a=numeric(0)
system.time(
{
while(length(a)<1e7){
a[[length(a)+1]]=pi
}
}
)
# user system elapsed
# 5.29 0.38 5.69
Forse hai già notato che length
può richiedere molto tempo. Se sostituiamo length
con un contatore:
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
Come menzionato da altri utenti, la pre-allocazione del vettore è molto utile. Ma questo è un compromesso tra velocità e utilizzo della memoria se non sai di quanti loop hai bisogno per ottenere il risultato.
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 metodo intermedio consiste nell'aggiungere gradualmente blocchi di risultati.
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
; oppure potresti fare vector = vector + valori. Ma potrei fraintendere il tuo caso d'uso