在纯dplyr或data.table中是否有一种方法可以按一列进行分组,然后减少每一组,以使它们最终只包含与另一列的值相交的行?
这里是一个例子:
library(tibble)
library(dplyr)
classification <- rep(c("A", "B", "C"), each = 10)
set.seed(123)
id.list <- lapply(1:3, function(i) sample(letters[1:7], 10, replace = T))
dtbl <- tibble(classification = classification, id = unlist(id.list), value = round(runif(30, 50, 99)))
这将产生以下结果:
# A tibble: 30 x 3
classification id value
<chr> <chr> <dbl>
1 A g 84
2 A g 89
3 A c 51
4 A f 73
5 A c 87
6 A b 61
7 A b 66
8 A f 61
9 A c 57
10 A e 70
11 B d 70
12 B f 68
13 B f 57
14 B a 57
15 B b 61
16 B c 73
17 B e 63
18 B c 92
19 B c 52
20 B a 72
21 C d 89
22 C a 56
23 C a 77
24 C e 60
25 C c 56
26 C b 87
27 C g 94
28 C b 68
29 C a 83
30 C f 55
出现在每个分类组中的id的值为b
,c
,e
和f
。我可以通过执行以下操作获得所需的结果:
common.id <- Reduce(intersect, id.list)
dtbl.intersect <- filter(dtbl, id %in% common.id) %>%
arrange(classification, id, value)
哪个给我:
# A tibble: 20 x 3
classification id value
<chr> <chr> <dbl>
1 A b 61
2 A b 66
3 A c 51
4 A c 57
5 A c 87
6 A e 70
7 A f 61
8 A f 73
9 B b 61
10 B c 52
11 B c 73
12 B c 92
13 B e 63
14 B f 57
15 B f 68
16 C b 68
17 C b 87
18 C c 56
19 C e 60
20 C f 55
但是我不喜欢为了创建common.id
而必须脱离dplyr管道。是否可以在dplyr或data.table中执行整个过程?
编辑
正如答复中正确指出的那样:我正在寻找一种不使用id.list
列表的解决方案(这只是MWE的一部分)。一个更广泛的问题是:dplyr / data.table分组操作是否创建了一个可由reduce函数使用的“某处”列表?
答案 0 :(得分:3)
您可以按以下方式使用$> posts = Post.where(state: 'published')
#=> #<ActiveRecord::Relation [#<Post id: 50, title: 'Wonderful', user_id: 39, state: 'published'>, #<Post id: 53, title: 'Alpha', user_id: 39, state: 'published'>]>
$> posts.assign_attributes(state: 'pending') #=> nil
$> posts
#=> #<ActiveRecord::Relation [#<Post id: 50, title: 'Wonderful', user_id: 39, state: 'pending'>, #<Post id: 53, title: 'Alpha', user_id: 39, state: 'pending'>]>
软件包:
data.table
答案 1 :(得分:1)
您可以(添加purrr
来做到)
dtbl %>%
filter(id %in% reduce(id.list, intersect)) %>%
arrange(classification, id, value)
或者:
dtbl %>%
filter(id %in% Reduce(intersect, id.list)) %>%
arrange(classification, id, value)
或者该问题是否更着重于创建id.list:
dtbl %>%
mutate(n = n_distinct(classification)) %>%
group_by(id) %>%
filter(n_distinct(classification) == n) %>%
select(-n) %>%
arrange(classification, id, value)
答案 2 :(得分:1)
有2种使用data.table
的(速度)可比较的方法:
mtd0 <- function(DT) {
IDs <- DT[, unique(id)]
invisible(DT[, IDs <<- intersect(IDs, id), classification])
DT[id %in% IDs][order(classification, id, value)]
}
mtd1 <- function(DT) {
DT[DT[, .(id=Reduce(intersect, split(id, classification)))], on=.(id), nomatch=0L][
order(classification, id, value)]
}
我认为您的id.list
使我们感到困惑,尽管您只是使用它来创建MWE,但使我们认为它可以作为独立变量使用。
数据:
library(data.table) #data.table_1.12.4
set.seed(0L)
nr <- 1e7
nclass <- 1e4
nid <- 1e2
dat <- data.table(classification=sample(nclass, nr, TRUE),
id=sample(nid, nr, TRUE))[, value := .I]
setorder(dat, classification, id, value)
来自bench::mark(mtd0(dat), mtd1(dat))
的时间:
# A tibble: 2 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory time gc
<bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm> <list> <list> <list> <list>
1 mtd0(DT) 810.17ms 810.17ms 1.23 897MB 3.70 1 3 810.17ms <df[,3] [6,197,991 x 3]> <df[,3] [80,334 x 3]> <bch:tm> <tibble [1 x 3]>
2 mtd1(DT) 1.33s 1.33s 0.752 854MB 3.01 1 4 1.33s <df[,3] [6,197,991 x 3]> <df[,3] [94,322 x 3]> <bch:tm> <tibble [1 x 3]>
答案 3 :(得分:0)
这就是我要做的:
setDT(dtbl)
result <- dtbl[id %chin% Reduce(intersect, id.list)] # %chin% is fast %in% for characters
setorder(result, classification, id, value)