2016-01-13 2 views
7

Предположим, что у меня есть этот вход:Прогрессивное конкатенации колонки группой

   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 

Я хотел бы постепенно конкатенации значения str столбца переменной группы ID, как показано в следующем выводе:

   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 

Я пытался использовать функцию ave() с этим кодом:

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

, но он дает следующий результат, который не является именно то, что я хочу:

  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 

Конечно, я хотел бы избежать петли, так как я работаю на большой базе данных.

+0

Я боюсь, что вам нужно использовать цикл в этом случае, так как это последовательная проблема –

+0

Liam, я бы порекомендовал вам принять ответ на этот вопрос, а затем задать новый вопрос, вместо того чтобы добавлять больше вот этот. –

ответ

8

Вот возможное решение, сочетающее data.table с внутренним tapply, которые, кажется, чтобы получить, что вам нужно (вы можете использовать paste вместо toString, если вам нравится, это просто выглядит чище меня, что путь).

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 

Вы можете быть в состоянии улучшить его немного, используя

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

Это выглядит красиво и не стоит слишком долго на больших наборах данных, спасибо! –

9

Как насчет ave() с Reduce(). Функция Reduce() позволяет нам накапливать результаты по мере их расчета. Поэтому, если мы запустим его с помощью paste(), мы сможем скопировать вставные строки.

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

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

который дает обновленное кадр данных 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 

Примечание:function(...) paste(..., sep = ", ") также может быть function(x, y) paste(x, y, sep = ", "). (Спасибо Pierre Lafortune)

+0

Ницца один-мне нравится. –

+1

Проклятье, избили меня, поскольку я пытался выяснить '...' в функции 'paste'. Красиво сделано. – thelatemail

+0

Ха-ха, вы избили меня, а также часть «Уменьшить». ;) – cryo111

Смежные вопросы