用聚合在 R 中做子集很热吗?

Hot to do subset in R with aggregation?

我有一个包含 2 列的大型数据框(200000 行):group_id 和 user_id。一个用户可以属于多个组。我需要一个包含属于 3 个以上组的所有用户的 group_id、user_id 的结果数据框。

group_id  user_id
100       1
101       1
102       1
103       1
101       2
103       2

在上面的示例中,在结果数据框中我将只获得前 4 行。

df <- structure(list(group_id = c(100L, 101L, 102L, 103L, 101L, 103L
    ), user_id = c(1L, 1L, 1L, 1L, 2L, 2L)), .Names = c("group_id", 
    "user_id"), class = "data.frame", row.names = c(NA, -6L))

"data.table" 包使这变得简单。如果df是原始数据框,你可以做

library(data.table)
setDT(df)[, .SD[.N > 3], by = user_id]
#    user_id group_id
# 1:       1      100
# 2:       1      101
# 3:       1      102
# 4:       1      103

.N告诉我们每组有多少行(这里选择user_id),.SD选择所有列。所以 .SD[.N > 3] 为我们提供了超过三行的所有组。

注意:如果不想把原来的df改成数据table,可以用as.data.table()代替setDT()。但是,这将复制 df.

这是一个 dplyr 解决方案,但在看到@Richard 时我知道还有更好的 dplyr 方法:

library(dplyr)

df %>% 
    count(user_id) %>%
    filter(n > 3) %>%
    select(user_id) %>%
    inner_join(df, .)

## Joining by: "user_id"
##   group_id user_id
## 1      100       1
## 2      101       1
## 3      102       1
## 4      103       1

使用@Richard 的评论:

df %>%
    group_by(user_id) %>% 
    filter(n() > 3)

假设 'group_id' 每个 'user_id' 都是唯一的,使用 base R 的选项将是

 df[with(df, ave(user_id, user_id, FUN=length)>3),]
 #     group_id user_id
 #1      100       1
 #2      101       1
 #3      102       1
 #4      103       1