#r #dataframe #concatenation #aggregate #dplyr
#r #фрейм данных #объединение #агрегировать #dplyr
Вопрос:
Какой самый быстрый способ выполнить операцию, подобную объединению, над data.frame
in R
? Предположим, у меня есть следующая таблица:
df <- data.frame(content = c("c1", "c2", "c3", "c4", "c5"),
groups = c("g1", "g1", "g1", "g2", "g2"),
stringsAsFactors = F)
df$groups <- as.factor(df$groups)
Я хочу эффективно объединить содержимое ячеек в content
столбце по группам, чтобы получить эквивалент:
df2 <- data.frame(content = c("c1 c2 c3", "c4 c5"),
groups = c("g1", "g2"),
stringsAsFactors = F)
df2 $groups <- as.factor(df2 $groups)
Я бы предпочел некоторую dplyr
операцию, но не имею хорошей идеи, как ее применить.
Ответ №1:
Близкий родственник tapply
is aggregate
, который позволяет вам делать это:
aggregate(content ~ groups, df, paste, collapse = " ")
# groups content
# 1 g1 c1 c2 c3
# 2 g2 c4 c5
Факторы сохраняются:
str(.Last.value)
# 'data.frame': 2 obs. of 2 variables:
# $ groups : Factor w/ 2 levels "g1","g2": 1 2
# $ content: chr "c1 c2 c3" "c4 c5"
Поскольку вы упомянули, что ищете dplyr
подход, вы можете попробовать что-то вроде этого:
library(dplyr)
df %>% group_by(groups) %>% summarise(content = paste(content, collapse = " "))
# Source: local data frame [2 x 2]
#
# groups content
# 1 g1 c1 c2 c3
# 2 g2 c4 c5
Ответ №2:
Используя data.table
:
library(data.table)
dt = as.data.table(df)
dt[, paste(content, collapse = " "), by = groups]
# groups V1
#1: g1 c1 c2 c3
#2: g2 c4 c5
Поскольку скорость была упомянута в OP, data.table
и dplyr
довольно близки (базовые методы очень медленные, нет смысла их тестировать):
dt = data.table(content = sample(letters, 26e6, T), groups = LETTERS)
df = as.data.frame(dt)
system.time(dt[, paste(content, collapse = " "), by = groups])
# user system elapsed
# 5.37 0.06 5.65
system.time(df %>% group_by(groups) %>% summarise(paste(content, collapse = " ")))
# user system elapsed
# 7.10 0.13 7.67
Комментарии:
1. «Базовые методы очень медленные, нет смысла их тестировать». Теперь это просто подло (но я не отрицаю его истинности!) 🙂
Ответ №3:
Вот метод, использующий базовые tapply
splat<-with(df, tapply(content, groups, paste, collapse=" "))
df2<-data.frame(groups=names(splat), content=splat, stringsAsFactors=F)
df2$groups <- as.factor(df2$groups)
что дает вам
# groups content
# g1 g1 c1 c2 c3
# g2 g2 c4 c5
(дополнительные «g1 / g2» — это имена строк в data.frame)
Комментарии:
1. Спасибо! Я действительно ценю вашу помощь, это сэкономило мне много времени! =)