R语言 在可行的情况下按组划分子集



我想对我的数据行进行子集化

library(data.table); set.seed(333); n <- 100 
dat <- data.table(id=1:n, group=rep(1:2,each=n/2), x=runif(n,100,120), y=runif(n,200,220), z=runif(n,300,320))
> head(dat)
id group        x        y        z
1:  1     1 109.3400 208.6732 308.7595
2:  2     1 101.6920 201.0989 310.1080
3:  3     1 119.4697 217.8550 313.9384
4:  4     1 111.4261 205.2945 317.3651
5:  5     1 100.4024 212.2826 305.1375
6:  6     1 114.4711 203.6988 319.4913

在每个小组内的几个阶段。我需要自动化此操作,并且可能会发生子集为空的情况。例如,仅关注组 1,

dat1 <- dat[1:50]
> s <-subset(dat1,x>119)
> s
id group        x        y        z
1:  3     1 119.4697 217.8550 313.9384
2: 50     1 119.2519 214.2517 318.8567

第二步subset(s, y>219)是空的,但我仍然想subset(s,z>315)应用第三步。如果我手动设置阈值,Frank 在这里提供了一个出色的解决方案,可以输出

> f(dat1, x>119, y>219, z>315)
cond  skip
1: x > 119 FALSE
2: y > 219  TRUE
3: z > 315 FALSE
id group        x        y        z
1: 50     1 119.2519 214.2517 318.8567

并报告跳过了哪些部分。

我的问题是我需要同时将其应用于不同的组,其中每个组的阈值在单独的 data.table 中给出。目标是每组至少有一个id。例如,如果我的阈值为

c <- data.table(group=1:2, x=c(119,119), y=c(219,219), z=c(315,319))
> c
group   x   y   z
1:     1 119 219 315
2:     2 119 219 319

我想以

> res
id group        x        y        z
1: 50     1 119.2519 214.2517 318.8567
2: 55     2 119.2634 219.0044 315.6556

我可以在 for 循环中反复应用 Frank 的函数,但我相信有更聪明的方法可以节省时间。例如,我想知道该函数是否可以应用于data.table中的每个组。或者也许在整洁的宇宙中有一种方法,我还不是很熟悉。

使用标准评估的另一种可能方法:

#convert conditions into long format, storing operator in data.table as well
cond <- data.table(group=1:2, bop=c(`>`, `>`), x=c(119,119), y=c(219,219), z=c(315,319))
thres <- melt(cond, id.vars=c("group","bop"))
#convert data into long format and lookup filter and thresholds
mdat <- melt(dat, id.vars=c("id", "group"))[
thres, on=.(group, variable), c("bop","thres") := mget(c("bop","i.value"))]
#apply filtering
ss <- mdat[mapply(function(f, x, y) f(x, y), bop, value, thres)]
#apply sequential subsetting
dat[id %in% ss[, {
idx <- id
ans <- .SD[, {
x <- intersect(idx, id)
if(length(x) > 0) {
idx <- x
}
idx
}, .(variable)]
ans[variable==last(variable), V1]
}, .(group)]$V1
]

输出:

id group        x        y        z
1: 50     1 119.2519 214.2517 318.8567
2: 55     2 119.2634 219.0044 315.6556
3: 58     2 119.2211 214.0305 319.3097
4: 72     2 114.0802 217.7402 313.3655
5: 90     2 116.8115 215.1576 317.0261
6: 99     2 119.2964 212.9973 308.9360

数据:

library(data.table)
set.seed(333)
n <- 100
dat <- data.table(id=1:n, group=rep(1:2,each=n/2),
x=runif(n,100,120), y=runif(n,200,220), z=runif(n,300,320))

最新更新