汇总数据框每列的所有唯一值

8
我有一个大的数据框(1616610行,255列),我需要根据键将每一列的唯一值粘合在一起。
例如:
> data = data.frame(a=c(1,1,1,2,2,3),
              b=c("apples", "oranges", "apples", "apples", "apples", "grapefruit"),
              c=c(12, 22, 22, 45, 67, 28), 
              d=c("Monday", "Monday", "Monday", "Tuesday", "Wednesday", "Tuesday"))
> data
  a          b  c         d
1 1     apples 12    Monday
2 1    oranges 22    Monday
3 1     apples 22    Monday
4 2     apples 45   Tuesday
5 2     apples 67 Wednesday
6 3 grapefruit 28   Tuesday

我需要的是将每个255列中的唯一值聚合,并返回一个新的数据框,对于每个唯一值使用逗号分隔。像这样:
  a               b      c                  d
1 1 apples, oranges 12, 22             Monday
2 2          apples 45, 67 Tuesday, Wednesday
3 3      grapefruit     28           Thursday

我已经尝试使用 aggregate,如下:

output <- aggregate(data, by=list(data$a), paste, collapse=", ")

但对于这样规模的数据帧,它已经花费了太多时间(几个小时),而且往往我不得不完全终止进程。除此之外,这将汇总所有值,而不仅仅是唯一的值。有没有人有任何关于以下方面的提示:

1)如何改善大型数据集的聚合时间

2)然后获取每个字段的唯一值

顺便说一句,这是我在SO上的第一个帖子,所以感谢您的耐心。


对于那么大的数据,你可能需要使用 data.table。我不太擅长它的语法,但这里有一些人是专家。 - alistaire
感谢 @alistaire,我听说data.table在处理大型数据集方面表现很好,并尝试过使用它,但似乎无法理解这个问题的语法。 - bab2155
谢谢 @G.Grothendieck!那个很好用。 - bab2155
@G.Grothendieck,您能否将此重写为答案,以便我可以标记为已解决?谢谢! - bab2155
2个回答

7

从评论中移动:

library(data.table)

dt <- as.data.table(data)
dt[, lapply(.SD, function(x) toString(unique(x))), by = a]

提供:

   a               b      c                  d
1: 1 apples, oranges 12, 22             Monday
2: 2          apples 45, 67 Tuesday, Wednesday
3: 3      grapefruit     28            Tuesday

5

使用 dplyr,您可以执行以下操作:

编辑1

更新的答案消除了使用summarise_each(在dplyr 0.7.0中)引起的弃用警告。这使用summariseacross代替summarise_each

library(dplyr)

func_paste <- function(x) paste(unique(x), collapse = ', ')
data %>%
  group_by(a) %>%
  summarise(across(everything(), func_paste))

# Without "func_paste", using paste directly (from Alistaire's comment).
data %>%
  group_by(a) %>%
  summarise(across(everything(), ~ paste(unique(.), collapse = ', ')))

## # A tibble: 3 × 4
##       a b               c      d
##   <dbl> <chr>           <chr>  <chr>
## 1     1 apples, oranges 12, 22 Monday
## 2     2 apples          45, 67 Tuesday, Wednesday
## 3     3 grapefruit      28     Tuesday

先前的回答,会导致弃用警告(自dplyr 0.7.0起)

func_paste <- function(x) paste(unique(x), collapse = ', ')
data %>%
    group_by(a) %>%
    summarise_each(funs(func_paste))

##      a               b      c                  d
##  (dbl)           (chr)  (chr)              (chr)
##1     1 apples, oranges 12, 22             Monday
##2     2          apples 45, 67 Tuesday, Wednesday
##3     3      grapefruit     28            Tuesday

# Without "func_paste", using paste directly (from Alistaire's comment).
data %>%
  group_by(a) %>%
  summarise_each(funs(paste(unique(.), collapse = ', ')))

1
在这个表达式中,data %>% group_by(a) %>% summarise_each(funs(paste(unique(.), collapse = ', ')))。虽然它确实能够返回正确的结果,但速度比原来的aggregate函数慢。 - alistaire
1
@alistaire 谢谢你的测试并且消除了需要另外一个函数的需要。用 data.table 来实现速度是很快的,难以超越。 - steveb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接