2012-05-06 12 views
14

So che non è la prassi migliore in R utilizzare il ciclo for perché non ha prestazioni migliorate. Per quasi tutti i casi esiste una funzione della famiglia *apply che risolve i nostri problemi.Loop in R - È necessario utilizzare l'indice, ad ogni modo per evitare 'per'?

Tuttavia, sto affrontando una situazione in cui non vedo una soluzione alternativa.

ho bisogno di calcolare la variazione percentuale per i valori consecutivi:

pv[1] <- 0 
for(i in 2:length(x)) { 
    pv[i] <- (x[i] - x[i-1])/x[i-1] 
} 

Quindi, come potete vedere, devo usare sia l'elemento x[i], ma anche l'elemento x[i-1]. Usando le funzioni *apply, vedo solo come utilizzare x[i]. Posso comunque evitare i loop for?

risposta

18

Cosa avete offerto sarebbe la variazione frazionale, ma se moltiplicato per 100 si ottiene la "variazione percentuale":

pv<- vector("numeric",length(x)) 
pv[1] <- 0 
pv[-1] <- 100* (x[-1] - x[-length(x)])/ x[-length(x)] 

soluzione Vettorializzare. (E dovresti notare che i cicli for-down saranno tanto lenti quanto * applicare soluzioni ... semplicemente non così belli. Cerca sempre un approccio vettorizzato.)

Per spiegare un po 'di più: Il x[-length(x)] è il vector, , e il è il vettore x[2:length(x)] e le operazioni vettoriali in R eseguono le stesse operazioni del corpo del ciclo for, sebbene non utilizzino un ciclo esplicito. R prima costruisce le differenze in quei vettori spostati, , e quindi divide per x[1:(length{x-1)].

+0

Bella risposta DWin. In realtà non sapevo che cosa stava realizzando il poster, ma sono d'accordo al 100% sulla vettorizzazione.+1 –

+0

Risposta molto bella! Non sapevo che l'approccio vettoriale fosse il più veloce, pensavo fosse "lapply". Ma nell'ultima riga di codice, non dovrebbe essere 'x [-1] - x [-length (x)]'? –

+0

@ JoãoDaniel: Sì, dovrebbe. Modifica applicata. –

20

È possibile ottenere gli stessi risultati con:

pv <- c(0) 
y <- sapply(2:length(x), function(i) {pv <<- (x[i] - x[i-1])/x[i-1]}) 
c(0, y) 

Il ciclo per i problemi che una volta erano un problema sono stati ottimizzati. Spesso un ciclo for non è più lento e potrebbe persino essere più veloce della soluzione apply. Devi testarli entrambi e vedere. Scommetto che il tuo ciclo for è più veloce della mia soluzione.

MODIFICA: solo per illustrare la soluzione loop vs. apply e ciò che DWin discute sulla vettorizzazione, ho eseguito il benchmarking sulle quattro soluzioni utilizzando microbenchmark su una macchina win 7.

Unit: microseconds 
      expr  min  lq median  uq  max 
1 DIFF_Vincent 22.396 25.195 27.061 29.860 2073.848 
2  FOR.LOOP 132.037 137.168 139.968 144.634 56696.989 
3   SAPPLY 146.033 152.099 155.365 162.363 2321.590 
4 VECTORIZED_Dwin 18.196 20.063 21.463 23.328 536.075 

enter image description here

+0

Qual è la versione "DIF" e che cosa fa tutto il look test come? La soluzione di @VincentZoonekynd è la più veloce per me. – Tommy

+0

Dovrebbe essere stato DIFF per diff (Vincent's). Per essere onesti, con il benchmarking non dimenticate di prendere il * 100 dalla soluzione DWin poiché questo aggiunge un calcolo extra che è una percentuale (non una proporzione come la soluzione di tutti gli eles). –

+0

+1 per la bellezza del grafico! –

16

È inoltre possibile utilizzare diff:

c(0, diff(x)/x[-length(x)]) 
c(0, exp(diff(log(x))) - 1) 
+0

+1 Questo sembra essere il più veloce ... E mi piace la variante log/exp anche se non è così veloce. – Tommy

+0

Suggerimento per i cappelli: Devo ammettere che l'approccio diff() è un po 'più elegante della mia traduzione letterale in una soluzione vettoriale. Sono rimasto sorpreso dal fatto che non abbia avuto un benchmark migliore. –

+0

@DWin - quando I benchmark, usando 'diff' o non fa nessuna differenza. Ma usare 'c' invece della tua sostituzione è molto più veloce. Qualcosa è sospetto sui numeri di Tyler. L'ho eseguito su 'x <- runif (1e7)' ... – Tommy

Problemi correlati