2012-10-24 16 views
5

desidero eseguire una semplice operazione in R che viene fatto facilmente in Excel:Aggiunta di valori di una riga alla precedente in R

ho a col composto di 5045 voci denominate K. desidero crea una seconda colonna L dove il primo valore è L1 = 100 + K [1] il secondo è L2 = L1 + K [2], il terzo è L3 = L2 + K [3] e così via.

C'è un modo semplice per farlo in R? in Excel si deve solo tirare giù la colonna.

risposta

7

provare qualcosa di simile

L <- 100 + cumsum(K) 
+0

+1 Neat - Avevo perso quello quando ho iniziato a scrivere la mia risposta, solo per farmi capire quando avevo finito. –

+0

+1 Ho avuto difficoltà a trovare una soluzione vettoriale e sono tornato a usare un ciclo 'for'. I tempi nella mia risposta mostrano che questo è terribilmente lento rispetto all'utilizzo di "cumsum". –

4

Un approccio è quello di utilizzare cumsum() e imbrogliare un po '. Ad esempio, dato K:

K <- 1:10 

e mantenere le cose semplici sto aggiungendo 1 (non 100) per K[1], vogliamo produrre:

> 1 + K[1] 
[1] 2 
> (1 + K[1]) + K[2] 
[1] 4 
> ((1 + K[1]) + K[2]) + K[3] 
[1] 7 
.... 

Si tratta di una somma cumulativa. Dobbiamo imbrogliare un po 'con la costante che vuoi aggiungere al primo elemento, poiché desideriamo che questo influenzi il primo elemento, non che venga aggiunto a ciascun elemento. Quindi questo è sbagliato

> L <- cumsum(1 + K) 
> L 
[1] 2 5 9 14 20 27 35 44 54 65 

Quello che vogliamo davvero è:

> L <- cumsum(c(1, K))[-1] 
> L 
[1] 2 4 7 11 16 22 29 37 46 56 

In cui abbiamo concatenare il costante al vettore K come il primo elemento e applichiamo cumsum() a questo, ma cadere il primo elemento dell'output da cumsum().

Questo può naturalmente essere fatto in un modo un po 'più semplice:

> L <- 1 + cumsum(K) 
> L 
[1] 2 4 7 11 16 22 29 37 46 56 

cioè calcolare la cumusum() e poi aggiungere sulla costante (che ora vedo è ciò che @ gd047 ha suggerito nella loro risposta.)

0

Quanto segue mostra una soluzione basata su loop for. Questo probabilmente non è quello che vuoi in termini di velocità, dove le funzioni vettoriali come cumsum sono molto più veloci.

a = 1:10 
b = vector(mode = "numeric", length = length(a)) 
b[1] = 1 + a[1] 

for(idx in 2:length(a)) { 
    b[idx] = a[idx] + b[idx - 1] 
} 

Alcune timing:

require(rbenchmark) 

for_loop_solution = function(a) { 
    b = vector(mode = "numeric", length = length(a)) 
    b[1] = 1 + a[1] 

    for(idx in 2:length(a)) { 
     b[idx] = a[idx] + b[idx - 1] 
    } 
    return(invisible(b)) 
} 

cumsum_solution = function(a) { 
    return(1 + cumsum(a)) 
} 

sample_data = 1:10e3 
benchmark(for_loop_solution(sample_data), 
      cumsum_solution(sample_data), 
      replications = 100) 
          test replications elapsed relative user.self 
2 cumsum_solution(sample_data)   100 0.013 1.000  0.011 
1 for_loop_solution(sample_data)   100 3.647 280.538  3.415 
    sys.self user.child sys.child 
2 0.002   0   0 
1 0.006   0   0 

che dimostra che l'uso di cumsum dista poche centinaia di volte più veloce rispetto all'utilizzo di un esplicito ciclo for. Questo effetto sarà ancora più pronunciato quando la lunghezza di sample_data aumenta.

0

Come illustrato da Paul Hiemstra, la funzione integrata cumsum() è veloce. Ma la soluzione ciclo for può essere accelerata utilizzando il pacchetto del compilatore.

library(compiler) 
fls_compiled <- cmpfun(for_loop_solution) 

Poi utilizzando gli stessi dati corriamo benchmark come segue

benchmark(for_loop_solution(sample_data), 
      cumsum_solution(sample_data), 
      fls_compiled(sample_data), 
      replications = 100) 
          test replications elapsed relative user.self 
2 cumsum_solution(sample_data)   100 0.013 1.000  0.013 
3  fls_compiled(sample_data)   100 0.726 55.846  0.717 
1 for_loop_solution(sample_data)   100 4.417 339.769  3.723 
    sys.self user.child sys.child 
2 0.000   0   0 
3 0.006   0   0 
1 0.031   0   0 

Così utilizzare funzioni interne, ove possibile. E se non c'è un builtin, prova il pacchetto del compilatore. Fornisce spesso un codice più veloce.

Problemi correlati