2013-03-17 20 views
11

Mi sembra che questa sia una domanda abbastanza facile, ma per la vita di me non riesco a trovare la risposta. Ho un dataframe abbastanza standard, e quello che sto cercando di fare è sommare una colonna di valori fino a che non raggiungono un certo valore (o quel valore esatto o maggiore di esso), a quel punto cade un 1 in una nuova colonna (etichettata tenere) e riavvia la somma a 0.Somma cumulativa fino al raggiungimento massimo, quindi ripetere da zero nella riga successiva

Ho una colonna di minuti, le differenze tra i minuti, una colonna di mantenimento e una colonna di somma cumulativa (l'esempio che sto usando è molto più pulito del set di dati completo effettivo)

minutes  difference  keep  difference_sum 
1052991158  0   0   0 
1052991338  180   0   180 
1052991518  180   0   360 
1052991698  180   0   540 
1052991878  180   0   720 
1052992058  180   0   900 
1052992238  180   0   1080 
1052992418  180   0   1260 
1052992598  180   0   1440 
1052992778  180   0   1620 
1052992958  180   0   1800 

la somma differenza colonna è stata calcolata con il codice

caribou.sub$difference_sum<-cumsum(difference) 

Quello che mi piacerebbe fare è eseguire il codice sopra con la condizione che, quando il valore sommato raggiunge o 1470 o qualsiasi numero maggiore di quello, mette un 1 nella colonna keep e poi ricomincia la somma in seguito, e continua a correre per tutto il set di dati.

Grazie in anticipo, e se avete bisogno di ulteriori informazioni fatemelo sapere.

Ayden

+3

Vuol 'difference_sum' nuovo a 0 se 1470 è raggiunto? Un set di esempio leggermente più lungo, incluso quando 'difference_sum' incrocia la soglia, sarebbe d'aiuto. – alexwhan

+0

No, questo è quello che sto cercando di fare, la colonna della differenza di differenza è attualmente calcolata con il codice caribou.sub $ difference_sum <-cumsum (difference). Continua ad andare avanti fino al set di dati. – HeidelbergSlide

+0

OK, ma dopo aver superato la soglia, come si fa a calcolare la soglia successiva? Usi l'eccedenza oltre il 1470 o inizi a 0 dalla riga successiva? – alexwhan

risposta

7

Penso che questo è fatto meglio con un ciclo for, non può pensare di una funzione che potrebbe farlo fuori dalla scatola. Il seguente dovrebbe fare quello che vuoi (se ti capisco correttamente).

current.sum <- 0 
for (c in 1:nrow(caribou.sub)) { 
    current.sum <- current.sum + caribou.sub[c, "difference"] 
    carribou.sub[c, "difference_sum"] <- current.sum 
    if (current.sum >= 1470) { 
     caribou.sub[c, "keep"] <- 1 
     current.sum <- 0 
    } 
} 

Sentitevi liberi di commentare se non è esattamente quello che vuoi. Ma come sottolineato da alexwhan, la tua descrizione non è completamente chiara.

+0

Ah, perfetto, sì, lo fa esattamente. Tutto quello che dovevo fare era copiare e incollare ed eccolo lì. Grazie mille. – HeidelbergSlide

+0

La prima riga è 180 però. Dovrebbe essere 0? – Aaron

+0

Nell'esempio? Dovrebbe essere 0, l'ho appena cambiato. – HeidelbergSlide

7

Assumendo che il data.frame è df:

df$difference_sum <- c(0, head(cumsum(df$difference), -1)) 
# get length of 0's (first keep value gives the actual length) 
len <- sum(df$difference_sum %/% 1470 == 0) 
df$keep <- (seq_len(nrow(df))-1) %/% len 
df <- transform(df, difference_sum = ave(difference, keep, 
      FUN=function(x) c(0, head(cumsum(x), -1)))) 

#  minutes difference keep difference_sum 
# 1 1052991158  180 0    0 
# 2 1052991338  180 0   180 
# 3 1052991518  180 0   360 
# 4 1052991698  180 0   540 
# 5 1052991878  180 0   720 
# 6 1052992058  180 0   900 
# 7 1052992238  180 0   1080 
# 8 1052992418  180 0   1260 
# 9 1052992598  180 0   1440 
# 10 1052992778  180 1    0 
# 11 1052992958  180 1   180 
+2

Questo è esattamente dove stavo [email protected] - questo sarà marcatamente più veloce del ciclo – alexwhan

+0

Nessun "ripetere da zero" qui. Divergerà dall'altra risposta. –

+0

@MatthewLundberg, vuoi dire che l'op è interessata anche ai valori di cums corretti? Pensavo fosse solo per calcolare 'keep'? – Arun

1

io continuo a non capire circa quando la somma dovrebbe riavviarsi e se deve essere pari a zero, allora. Un risultato desiderato sarebbe di grande aiuto.

Tuttavia, non posso fare a meno di pensare che semplicemente indicizzazione e sottrazione sarebbero un modo semplice per farlo. Il codice seguente fornisce lo stesso risultato della soluzione di @Henrik.

df$difference_sum <- cumsum(df$difference) 
step <- (df$difference_sum %/% 1470) + 1 
k <- which(diff(step) > 0) + 1 
df$keep <- 0 
df$keep[k] <- 1 
step[k] <- step[k] - 1 
df$difference_sum <- df$difference_sum - c(0, df$difference_sum[k])[step] 
+0

Questo è molto vicino, ma poiché (come ho capito, e potrei sbagliarmi) stai usando la cumsum dell'intera colonna della differenza, l'eccesso dalla selezione precedente è incorporato nella selezione successiva, quindi succede anche una riga presto (il primo valore selezionato è al minuto 1620 ma lascia 150 minuti che dovrebbero essere ignorati ma vengono usati per la selezione successiva, quindi la selezione successiva avviene al minuto 1440 (perché la cessione dice i suoi 150 minuti in più di quanto non sia in realtà)) . Ha senso? Grazie per l'aiuto! – HeidelbergSlide

+0

Oh, capisco. Sì, penso che sia corretto (nel senso che la mia risposta non è giusta). Ancora una volta, un esempio più ampio con l'output desiderato sarebbe molto utile, anche se sembra che il problema sia stato risolto, quindi a questo punto potrebbe non valere la pena. – Aaron

Problemi correlati