Подтвердить что ты не робот

Свернуть все столбцы по столбцу ID

Я пытаюсь сделать что-то похожее на то, что ответили здесь, что дает мне 80% пути. У меня есть кадр данных с одним столбцом ID и несколькими информационными столбцами. Я хотел бы свернуть все других столбцов, чтобы для каждого идентификатора была только одна строка, а несколько записей разделены, например, точкой с запятой. Вот пример того, что у меня есть и чего я хочу.

ИМЕЮТ:

     ID  info1          info2
1 id101    one          first
2 id102   twoA second alias A
3 id102   twoB second alias B
4 id103 threeA  third alias A
5 id103 threeB  third alias B
6 id104   four         fourth
7 id105   five          fifth

ХОЧЕТ:

     ID          info1                          info2
1 id101            one                          first
2 id102     twoA; twoB second alias A; second alias B
3 id103 threeA; threeB   third alias A; third alias B
4 id104           four                         fourth
5 id105           five                          fifth

Здесь код, используемый для их создания:

have <- data.frame(ID=paste0("id", c(101, 102, 102, 103, 103, 104, 105)),
                   info1=c("one", "twoA", "twoB", "threeA", "threeB", "four", "five"), 
                   info2=c("first", "second alias A", "second alias B", "third alias A", "third alias B", "fourth", "fifth"),
                   stringsAsFactors=FALSE)
want <- data_frame(ID=paste0("id", c(101:105)),
                   info1=c("one", "twoA; twoB", "threeA; threeB", "four", "five"), 
                   info2=c("first", "second alias A; second alias B", "third alias A; third alias B", "fourth", "fifth"),
                   stringsAsFactors=FALSE)

Этот вопрос задал в основном тот же вопрос, но только один столбец "info". Я имею несколько других столбцов и хотел бы сделать это для всех из них.

Бонусные баллы для этого, используя dplyr.

4b9b3361

Ответ 1

Здесь используется опция summarise_each (что упрощает применение изменений ко всем столбцам, кроме переменных группировки) и toString:

require(dplyr)

have %>%
  group_by(ID) %>%
  summarise_each(funs(toString))

#Source: local data frame [5 x 3]
#
#     ID          info1                          info2
#1 id101            one                          first
#2 id102     twoA, twoB second alias A, second alias B
#3 id103 threeA, threeB   third alias A, third alias B
#4 id104           four                         fourth
#5 id105           five                          fifth

Или, если вы хотите, чтобы его разделили точки с запятой, вы можете использовать:

have %>%
  group_by(ID) %>%
  summarise_each(funs(paste(., collapse = "; ")))

Ответ 2

Старый добрый aggregate делает это просто отлично

aggregate(have[,2:3], by=list(have$ID), paste, collapse=";")

Вопрос: он масштабируется?

Ответ 3

Здесь a data.table решение.

library(data.table)
setDT(have)[, lapply(.SD, paste, collapse = "; "), by = ID]
#       ID          info1                          info2
# 1: id101            one                          first
# 2: id102     twoA; twoB second alias A; second alias B
# 3: id103 threeA; threeB   third alias A; third alias B
# 4: id104           four                         fourth
# 5: id105           five                          fifth

Ответ 4

Вот SQL решение ^ 1:

library(sqldf)
#Static solution
sqldf("
SELECT ID,
       GROUP_CONCAT(info1,';') as info1,
       GROUP_CONCAT(info2,';') as info2
FROM have
GROUP BY ID")

#Dynamic solution
concat_cols <- colnames(have)[2:ncol(have)]
group_concat <-
  paste(paste0("GROUP_CONCAT(",concat_cols,",';') as ", concat_cols),
        collapse = ",")
sqldf(
  paste("
      SELECT ID,",
      group_concat,"
      FROM have
      GROUP BY ID"))

# Same output for both static and dynamic solutions
#      ID         info1                         info2
# 1 id101           one                         first
# 2 id102     twoA;twoB second alias A;second alias B
# 3 id103 threeA;threeB   third alias A;third alias B
# 4 id104          four                        fourth
# 5 id105          five                         fifth

^ 1 - возможно, решение data.table будет работать лучше с миллионами строк, к счастью, у нас еще не так много генов:)

Ответ 5

library(stringr)
library(dplyr)
have %>% tbl_df %>% group_by(ID) %>% summarise_each(funs(str_c(., collapse="; ")))

Изменить 1: Так что tbl_df может не понадобиться, и вместо str_c пакета stringr вы можете использовать pastebase). И то, что указано выше, это группировать по столбцу идентификатора, а затем применять функцию str_c (или paste) к каждому оставшемуся столбцу для каждой группы.

Изменить 2: другое решение с помощью пакета data.table:

library(data.table)
dtbl <- as.data.table(have)
dtbl[,lapply(.SD, function(x) paste(x,collapse=";")), by=ID]

Вышеуказанное может быть быстрее, особенно если вы установили ключ:

setkey(dtbl, ID)

"Гибридное" решение: вы можете использовать синтаксис dplyr для data.tables! Например:

dtbl %>% tbl_dt %>%
     group_by(ID) %>% 
     summarise_each(funs(paste(., collapse="; ")))