通过dplyr中的多列索引/键进行子集化(具有data.table soln)

时间:2014-02-20 18:22:51

标签: r data.table dplyr

我正在寻找一种方法来分组(或重新思考我如何处理任务)下面的情况留在dplyr而不是“诉诸”data.table我的分析在此块完成之前/之后在dplyr。

情况:给定一个具有多个复制的模拟数据集,我想基于两列密钥(ID和REP)对/ dplyr :: filter进行子集化。

libs <- c("dplyr", "data.table")
lapply(libs, require, character.only = T)

# minimally reproducible example

# dataset
dat <- expand.grid(ID = 1:3, REP = 1:5, TIME = 1:3)
dat <- dat[order(dat$REP, dat$ID, dat$TIME),]
dat$CONC <- runif(nrow(dat), 1, 10)

# key/index
set.seed(1235)
ID_sample <- sample(unique(dat$ID), size = 5, replace = TRUE)
REP_sample <- sample(unique(dat$REP), size = 5, replace = TRUE)
key <- data.frame(ID = ID_sample, REP = REP_sample)


# data table solution
dt <- data.table(dat)
setkey(dt, ID, REP)
dt_subset <- dt[J(key)]

data.table解决方案产生以下结果:

初始数据结构:

   ID REP TIME     CONC
1   1   1    1 1.310819
2   1   1    2 2.371361
3   1   1    3 7.621165
4   2   1    1 1.010229
5   2   1    2 4.520830
6   2   1    3 5.162452
...
40  2   5    1 6.629885
41  2   5    2 9.680233
42  2   5    3 8.445726
43  3   5    1 3.835254
44  3   5    2 2.917229
45  3   5    3 7.592465

生成密钥和生成的子集:

> key
  ID REP
1  1   3
2  2   3
3  1   4
4  3   3
5  3   2

> dt[J(key)]
    ID REP TIME     CONC
 1:  1   3    1 3.038205
 2:  1   3    2 5.361020
 3:  1   3    3 8.137065
 4:  2   3    1 1.053889
 5:  2   3    2 2.689412
 6:  2   3    3 7.136503
 7:  1   4    1 9.137392
 8:  1   4    2 6.556821
 9:  1   4    3 2.206285
10:  3   3    1 4.330937
11:  3   3    2 4.254630
12:  3   3    3 8.819154
13:  3   2    1 4.508456
14:  3   2    2 7.286893
15:  3   2    3 5.896521

有没有办法在dplyr中使用这个多列索引进行过滤?

到目前为止,我唯一想到的“解决方案”是创建一个新列,如下所示:

dat <- transform(dat, ID_REP = paste0(ID, '_', REP))
KEY <- paste0(ID_sample, '_', REP_sample)
filter(dat, ID_REP %in% KEY)

有效:

       ID REP TIME     CONC ID_REP
1   3   2    1 4.029622    3_2
2   3   2    2 5.786582    3_2
3   3   2    3 2.846836    3_2
4   1   3    1 4.968823    1_3
5   1   3    2 6.940782    1_3
6   1   3    3 5.017697    1_3
7   2   3    1 7.571442    2_3
8   2   3    2 6.350095    2_3
9   2   3    3 3.924427    2_3
10  3   3    1 6.360991    3_3
11  3   3    2 3.273693    3_3
12  3   3    3 4.029781    3_3
13  1   4    1 6.617855    1_4
14  1   4    2 1.910202    1_4
15  1   4    3 5.496817    1_4

但是不够优雅,并且不提供易于扩展的解决方案。

2 个答案:

答案 0 :(得分:5)

您正在寻找semi join

semi_join(dat, key)

答案 1 :(得分:0)

假设您想要每个键的CONC变量的总和,

    aggregate(CONC~ID+REP+TIME,data=subset(dat,dat$ID %in% key$ID & dat$REP %in% key$REP),sum)

这会给你你想要的吗?