【问题标题】:Group-wise subsetting where feasible可行的分组子集
【发布时间】:2019-08-12 21:53:55
【问题描述】:

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

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&gt;219) 会空出来,但我仍然想应用第三步subset(s,z&gt;315)。如果我要手动设置阈值,Frank 提供了一个出色的解决方案here 输出

> 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 中的每个组。或者也许在 tidyverse 中有一种方法,我还不太熟悉。

【问题讨论】:

    标签: r data.table subset tidyverse


    【解决方案1】:

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

    #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))
    

    【讨论】:

    • 谢谢!不幸的是,即使有几个满足所有三个条件,它每组只输出一个条目。我检查了cond &lt;- data.table(group=1:2, bop=c(>, >), x=c(119,114), y=c(219,212), z=c(315,307)),它应该至少输出 ID 91、92 等。
    • 修复了last 的用法。 dat[group==2 &amp; x&gt;114 &amp; y&gt;212] 不是空集,因此我们需要删除 91, 92
    猜你喜欢
    • 2019-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 2012-09-10
    • 1970-01-01
    相关资源
    最近更新 更多