2016-01-13 7 views
7

Angenommen, ich habe diese Eingabe:Progressive Verkettung einer Spalte von einer Gruppe

   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 

Ich mag progressiv die Werte der str Spalte durch die variable Gruppe verketten ID, wie in dem folgenden Ausgang zeigte:

   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 

ich versuchte, die ave() Funktion mit diesem Code zu verwenden:

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

aber es gibt die folgende Ausgabe, die nicht genau das, was ich will:

  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 

Natürlich ich Schleifen vermeiden möchten, wie ich auf einer großen Datenbank arbeiten.

+0

Ich fürchte, Sie müssen Schleife in diesem Fall verwenden, da dies ein sequenzielles Problem ist –

+0

Liam, ich würde Ihnen empfehlen, eine Antwort auf diese Frage zu akzeptieren und dann eine neue Frage stellen, anstatt mehr hinzuzufügen dieses. –

Antwort

8

Hier ist eine mögliche Lösung data.table mit einer inneren tapply Kombination, die Sie scheint, was Sie brauchen (Sie paste statt toString verwenden können, wenn Sie mögen, es sieht einfach sauber mir auf diese Weise).

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 

Unter Umständen können Sie es ein bisschen verbessern

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

Das sieht gut aus und sollte bei großen Datensätzen nicht zu lange dauern, danke! –

9

Wie wäre es mit ave()Reduce() verwenden. Die Funktion Reduce() ermöglicht es uns, die Ergebnisse so zu berechnen, wie sie berechnet werden. Wenn wir es also mit paste() ausführen, können wir die eingefügten Strings ansammeln.

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

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

, die die aktualisierten Datenrahmen 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 

Hinweis gibt:function(...) paste(..., sep = ", ") auch function(x, y) paste(x, y, sep = ", ") sein könnte. (Danke Pierre Lafortune)

+0

Nice one- Ich mag. –

+1

Verdammt, schlage mich dazu, als ich versuchte, die '...' in der 'Einfügen'-Funktion herauszufinden. Schön gemacht. – thelatemail

+0

Haha, du hast mich auch mit dem 'Reduce'-Teil geschlagen. ;) – cryo111