2016-02-12 7 views
7

Ich suche nach einer Möglichkeit zu tun, was wäre das Äquivalent einer kumulativen Summe in R für String/Zeichen formatierten Text anstelle von Zahlen. Die verschiedenen Textfelder sollten verkettet werden.Entspricht cumsum für string in R

z. im Datenrahmen "df":

Spalte A enthält den Eingang, Spalte B das gewünschte Ergebnis.

A  B 
1 banana banana 
2 boats banana boats 
3 are  banana boats are 
4 awesome banana boats are awesome 

Derzeit bin ich der Lösung dies über die folgende Schleife

df$B <- "" 

for(i in 1:nrow(df)) { 
    if (length(df[i-1,"A"]) > 0) { 
     df$B[i] <- paste(df$B[i-1],df$A[i]) 
    } else { 
     df$B[i] <- df$A[i] 
    } 
} 

Ich frage mich, ob es eine elegantere/schnellere Lösung existiert.

+0

Es ist gar nicht "cumsum"! –

+0

Ist Leistung ein Problem? – Heroka

+2

Ich _think_ die klassische 'cumpaste' erschien [** hier **] (http://stackoverflow.com/questions/24862046/cumulative-pasting-concatenating-values-grouped-by-another-variable-in-r/24864007 # 24864007) zuerst (mögliches Duplikat). Cudos zu @alexis_laz. – Henrik

Antwort

9
(df$B <- Reduce(paste, as.character(df$A), accumulate = TRUE)) 
# [1] "banana"  "banana boats"  "banana boats are" "banana boats are awesome" 
+1

Beeindruckend und unglaublich schnell. (auf einem Eingabevektor von 1000 Strings, 20x schneller als meine Lösung) – Heroka

+0

@Heroka Reduce ist nur eine 'for' Schleife. – Roland

+0

@Roland und so ist sapply, aber auf meiner Maschine "Reduce" blies die anderen Antworten aus dem Park. Ich denke, es ist das "akkumulieren = WAHR". – Heroka

4

Ich weiß nicht, ob es schneller ist, aber zumindest der Code kürzer:

sapply(seq_along(df$A),function(x){paste(A[1:x], collapse=" ")}) 

Dank Rolands Kommentar, wurde mir klar, dass dies eine der seltenen Vorkommnissen war, wo eine for-Schleife sein könnte nützlich, da es uns die wiederholte Indizierung erspart. Es unterscheidet sich von OPs, wie es bei 2 beginnt, die Notwendigkeit für die if-Anweisung in der Forloop speichern.

res <- c(NA, length(df1$A)) 
res[1] <- as.character(df1$A[1]) 
for(i in 2:length(df1$A)){ 
    res[i] <- paste(res[i-1],df1$A[i]) 
} 
res 
4

Wir versuchen

i1 <- sequence(seq_len(nrow(df1))) 
tapply(df1$A[i1], cumsum(c(TRUE,diff(i1) <=0)), 
        FUN= paste, collapse=' ') 

Oder

i1 <- rep(seq(nrow(df1)), seq(nrow(df1))) 
tapply(i1, i1, FUN= function(x) 
      paste(df1$A[seq_along(x)], collapse=' '))