2017-02-24 2 views
1

ich einen Datenrahmen, die ein bisschen wie folgt aussieht:Wrapping kumulative Summe aus einem Satz Reihe in R beginnend

wt <- data.frame(region = c(rep("A", 5), rep("B", 5)), time = c(1:5, 1:5), 
       start = c(rep(2,5), rep(4, 5)), value = rep(1, 10)) 

Die Werte in der value Spalte beliebige Zahlen sein könnten (ich in einem sehr großen arbeite Datensatz), aber jede Region wird über eine Zeitreihe mit gleicher Länge sein und einen einzigen Startpunkt haben.

Ich möchte eine kumulative Summe innerhalb jeder Region erstellen, die am Anfangspunkt beginnt, sich in der Zeitreihe vorwärts zu bewegen und in die Zeilen vor dem Startpunkt in der Zeitreihe zu springen.

Die vollständige Datentabelle, mit dem Ergebnis bestimmt, würde wie folgt aussehen:

region time  start value result 
A   1  2  1  5 
A   2  2  1  1 
A   3  2  1  2 
A   4  2  1  3 
A   5  2  1  4 
B   1  4  1  3 
B   2  4  1  4 
B   3  4  1  5 
B   4  4  1  1 
B   5  4  1  2 

Eine einfache Umwandlung der Zeitspalte von cumsum gefolgt funktioniert nicht, da die Funktion über Zeile, um sie interessiert und nicht jeder bestimmter Faktor.

, die mit im Auge, ich auf einer riesige Datentabelle am Betrieb und Laufzeit ist absolut ein Anliegen, so dass jede Lösung muss vermeiden Nachbestellung Reihen.

Ideen, wie man das macht? Danke im Voraus.

EDIT: Betrachten sich Zeit, um einen Zyklus wie Stunden an einem Tag sein - und zum Beispiel, wenn die Startzeit ist 2, das heißt Beobachtungen an einer Instanz von Zeit 2 und enden am nächsten Start 1.

+0

Die Logik von 'Ergebnis ist nicht klar – akrun

+0

@akrun Anhäufung der Spalte' Wert 'beginnt wo 'Zeit == Start' und endet wo' Zeit == Start-1'. Wenn die Startzeit nicht 1 ist, sollte die Akkumulation in die erste Zeile der Region übertragen werden. – ctenochaetus

+0

In diesem Fall scheint die erwartete Ausgabe falsch zu sein. Wenn wir die Region 'A' nehmen, dann ist Zeit == Start ist die zweite Reihe, und Zeit == Start-1 ist die 3. Reihe, – akrun

Antwort

2

Wir können dies auf effiziente Art und Weise tun mit data.table

library(data.table) 
setDT(wt)[time>=start, result := seq_len(.N), region] 
wt[, Max := max(result, na.rm = TRUE), region] 
wt[is.na(result), result := Max +seq_len(.N) , region][, Max := NULL][] 
# region time start value result 
#1:  A 1  2  1  5 
#2:  A 2  2  1  1 
#3:  A 3  2  1  2 
#4:  A 4  2  1  3 
#5:  A 5  2  1  4 
#6:  B 1  4  1  3 
#7:  B 2  4  1  4 
#8:  B 3  4  1  5 
#9:  B 4  4  1  1 
#10:  B 5  4  1  2 
+0

Das sieht so aus, als ob es funktioniert! Wo im Code ist die Spalte "Wert" ausgewählt, um das Ergebnis zu berechnen? – ctenochaetus

+1

Nevermind, habe das gehandhabt (siehe meine Antwort unten) – ctenochaetus

+0

@ctenochaetus Okay, ich sehe, dass deine Spalte 'value' eine Sequenz ist, also ja, du kannst sie in 'cumsum' ändern, wenn es andere Werte gibt wie die, die du gepostet hast – akrun

1

akrun-Lösung für das Beispiel funktioniert ich habe (also ich es als Antwort akzeptiert), aber hier ist eine Version, die für alle Werte in der value Spalte funktioniert :

library(data.table) 
setDT(wt)[time>=start, result := cumsum(value), region] 
wt[, Max := max(result, na.rm = TRUE), region] 
wt[is.na(result), result := Max +cumsum(value) , region][, Max := NULL][] 

Nur Hinzufügen der ... leider cumsum Funktion anstelle einer berechneten Sequenz.