2016-01-13 15 views
7

Supponiamo che ho questo ingresso:progressiva concatenazione di una colonna da un gruppo

   ID  date_1  date_2  str 
1   1 2010-07-04 2008-01-20 A 
2   2 2015-07-01 2011-08-31 C 
3   3 2015-03-06 2013-01-18 D 
4   4 2013-01-10 2011-08-30 D 
5   5 2014-06-04 2011-09-18 B 
6   5 2014-06-04 2011-09-18 B 
7   6 2012-11-22 2011-09-28 C 
8   7 2014-06-17 2013-08-04 A 
10   7 2014-06-17 2013-08-04 B 
11   7 2014-06-17 2013-08-04 B 

desidero per concatenare progressivamente i valori della colonna str dalla variabile gruppo ID, come indicato nella seguente output:

   ID  date_1  date_2  str 
1   1 2010-07-04 2008-01-20 A 
2   2 2015-07-01 2011-08-31 C 
3   3 2015-03-06 2013-01-18 D 
4   4 2013-01-10 2011-08-30 D 
5   5 2014-06-04 2011-09-18 B 
6   5 2014-06-04 2011-09-18 B,B 
7   6 2012-11-22 2011-09-28 C 
8   7 2014-06-17 2013-08-04 A 
10   7 2014-06-17 2013-08-04 A,B 
11   7 2014-06-17 2013-08-04 A,B,B 

ho cercato di utilizzare la funzione ave() con questo codice:

within(table, { 
    Emp_list <- ave(str, ID, FUN = function(x) paste(x, collapse = ",")) 
}) 

ma dà il seguente risultato, che non è esattamente quello che voglio:

  ID  date_1  date_2  str 
1   1 2010-07-04 2008-01-20  A 
2   2 2015-07-01 2011-08-31  C 
3   3 2015-03-06 2013-01-18  D 
4   4 2013-01-10 2011-08-30  D 
5   5 2014-06-04 2011-09-18  B,B 
6   5 2014-06-04 2011-09-18  B,B 
7   6 2012-11-22 2011-09-28  C 
8   7 2014-06-17 2013-08-04  A,B,B 
10  7 2014-06-17 2013-08-04  A,B,B 
11  7 2014-06-17 2013-08-04  A,B,B 

Certo che mi piacerebbe evitare loop, come io lavoro su un database di grandi dimensioni.

+0

Ho paura di dover utilizzare il ciclo in questo caso, poiché questo è un problema sequenziale –

+0

Liam, ti consiglierei di accettare una risposta a questa domanda e poi fare una nuova domanda invece di aggiungere altro a questo. –

risposta

8

Ecco una possibile soluzione che combina data.table con un interno tapply che sembrano ottenere quello che ti serve (si può usare al posto di pastetoString se ti piace, sembra proprio più pulito per me in quel modo).

library(data.table) 
setDT(df)[, Str := tapply(str[sequence(1:.N)], rep(1:.N, 1:.N), toString), by = ID] 
df 
#  ID  date_1  date_2 str  Str 
# 1: 1 2010-07-04 2008-01-20 A  A 
# 2: 2 2015-07-01 2011-08-31 C  C 
# 3: 3 2015-03-06 2013-01-18 D  D 
# 4: 4 2013-01-10 2011-08-30 D  D 
# 5: 5 2014-06-04 2011-09-18 B  B 
# 6: 5 2014-06-04 2011-09-18 B B, B 
# 7: 6 2012-11-22 2011-09-28 C  C 
# 8: 7 2014-06-17 2013-08-04 A  A 
# 9: 7 2014-06-17 2013-08-04 B A, B 
# 10: 7 2014-06-17 2013-08-04 B A, B, B 

Si può essere in grado di migliorare un po 'utilizzando

setDT(df)[, Str := {Len <- 1:.N ; tapply(str[sequence(Len)], rep(Len, Len), toString)}, by = ID] 
+1

Questo sembra bello e non dovrebbe richiedere troppo tempo su dataset di grandi dimensioni, grazie! –

9

Come su ave() con Reduce(). La funzione Reduce() ci consente di accumulare i risultati non appena vengono calcolati. Quindi se lo eseguiamo con paste() possiamo accumulare le stringhe incollate.

f <- function(x) { 
    Reduce(function(...) paste(..., sep = ", "), x, accumulate = TRUE) 
} 

df$str <- with(df, ave(as.character(str), ID, FUN = f) 

che dà il frame di dati aggiornati df

ID  date_1  date_2  str 
1 1 2010-07-04 2008-01-20  A 
2 2 2015-07-01 2011-08-31  C 
3 3 2015-03-06 2013-01-18  D 
4 4 2013-01-10 2011-08-30  D 
5 5 2014-06-04 2011-09-18  B 
6 5 2014-06-04 2011-09-18 B, B 
7 6 2012-11-22 2011-09-28  C 
8 7 2014-06-17 2013-08-04  A 
10 7 2014-06-17 2013-08-04 A, B 
11 7 2014-06-17 2013-08-04 A, B, B 

Nota:function(...) paste(..., sep = ", ") potrebbe anche essere function(x, y) paste(x, y, sep = ", "). (Grazie Pierre Lafortune)

+0

Bello, mi piace. –

+1

Dannazione, bastonatemi mentre cercavo di capire il '...' nella funzione 'incolla'. Ben fatto. – thelatemail

+0

Haha, mi hai battuto anche con la parte 'Reduce'. ;) – cryo111