Свернуть все столбцы по столбцу 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.
Ответы
Ответ 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
вы можете использовать paste
(в base
). И то, что указано выше, это группировать по столбцу идентификатора, а затем применять функцию 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="; ")))