2012-10-24 9 views
5

I jak przeprowadzić prostą operację w R, które są łatwe do wykonania w Excelu:dodawanie wartości z rzędu poprzedniego tym, że R

mam col składający się z 5045 pozycji zwanej K. chciałbym utwórz drugą kolumnę L, gdzie pierwsza wartość to L1 = 100 + K [1] druga to L2 = L1 + K [2], trzecia to L3 = L2 + K [3] i tak dalej.

Czy istnieje prosty sposób to zrobić w R? w Excelu wystarczy ściągnąć col.

Odpowiedz

7

spróbować czegoś jak

L <- 100 + cumsum(K) 
+0

+1 Czysty - przegapiłem to, gdy zacząłem pisać moją odpowiedź, tylko po to, by zaatakować mnie, gdy byłem już prawie skończony. –

+0

+1 Trudno mi było znaleźć wektoryzowane rozwiązanie i powróciłem do korzystania z pętli 'for'. Czasy w mojej odpowiedzi pokazują, że jest to strasznie powolne w porównaniu do używania 'cumsum'. –

4

Jednym podejściem jest użycie cumsum() i oszukać trochę. Na przykład, biorąc pod uwagę K:

K <- 1:10 

i zachować rzeczy proste dodaję 1 (nie 100) do K[1] chcemy produkować:

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

Jest to skumulowana suma. Musimy trochę oszukiwać ze stałą, którą chcemy dodać do pierwszego elementu, ponieważ chcemy tylko, aby wpłynęło na ten pierwszy element, a nie dodawać go do każdego elementu. Stąd to źle

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

Co właściwie chcemy to:

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

w którym łączymy stałe do wektora K jako pierwszy element i zastosować cumsum() do tego, ale spadnie pierwszy element z wyjścia z cumsum().

Można to oczywiście zrobić w nieco prostszy sposób:

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

czyli obliczyć cumusum() i następnie dodać na stałe (co teraz widzisz to co @ gd047 zasugerował w ich odpowiedź.)

0

Poniżej przedstawiono rozwiązanie oparte na pętli for. To prawdopodobnie nie jest to, co chcesz pod względem szybkości, gdzie wektory funkcji, takich jak cumsum są znacznie szybsze.

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] 
} 

Niektóre czasy:

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 

który pokazuje, że przy użyciu cumsum jest kilkaset razy szybciej niż przy użyciu jawne dla pętli. Efekt ten będzie jeszcze bardziej wyraźny, gdy zwiększy się długość sample_data.

0

Jak pokazuje Paul Hiemstra, wbudowana funkcja cumsum() jest szybka. Ale rozwiązanie pętli for może zostać przyspieszone za pomocą pakietu kompilatora.

library(compiler) 
fls_compiled <- cmpfun(for_loop_solution) 

Następnie przy użyciu tych samych danych niech uruchomić benchmark następująco

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 

więc używać funkcji wbudowanych w miarę możliwości. A jeśli nie ma wbudowanego, wypróbuj pakiet kompilatora. Często zapewnia szybszy kod.

Powiązane problemy