【问题标题】:Group-wise conditional subsetting where feasible可行的分组条件子集
【发布时间】:2019-12-19 06:27:42
【问题描述】:

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

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

分几个阶段,除非它导致一个空子集。在这种情况下,我想跳过那个特定的子集。在earlier question 中,Frank 找到了一个很好的解决方案:

f = function(x, ..., verbose=FALSE){
  L   = substitute(list(...))[-1]
  mon = data.table(cond = as.character(L))[, skip := FALSE]

  for (i in seq_along(L)){
    d = eval( substitute(x[cond, verbose=v], list(cond = L[[i]], v = verbose)) )
    if (nrow(d)){
      x = d
    } else {
      mon[i, skip := TRUE]
    }    
  }
  print(mon)
  return(x)
}

我可以在其中手动输入数据和每个变量的截止值。

> f(dat, x > 119, y > 219, y > 1e6)
        cond  skip
1:   x > 119 FALSE
2:   y > 219 FALSE
3: y > 1e+06  TRUE
   id  group         x        y        z
1: 55      2  119.2634 219.0044 315.6556

我现在想知道如何将这个(或更好的东西!)应用于截止点位于第二个 data.table 中的情况

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

并分别为每个组指定。

如果我要使用f(.),我想将c 加入dat,但无法弄清楚。但也许完全有一种更聪明的方法。

【问题讨论】:

    标签: r data.table subset


    【解决方案1】:

    首先,我将更改c 的构造方式。您目前已将其设置为每个过滤器一列,但长格式将允许您在同一列上使用多个过滤器,类似于您的初始示例(即 y 上的两个过滤器):

    c <- data.table(group=c(1,2,1,2,1,2,1),variable = c("x","x","y","y","z","z","y"), c_val = c(110,119,210,219,310,319,1e6))
    c[, c_id := 1:.N]
    c
           group variable   c_val c_id
    1:     1        x     110    1
    2:     2        x     119    2
    3:     1        y     210    3
    4:     2        y     219    4
    5:     1        z     310    5
    6:     2        z     319    6
    7:     1        y 1000000    7
    

    然后您可以将过滤器合并到您的数据中。

    dat_cut <- melt(dat, id.vars = c("id", "group"), value.name = "dat_val")
    output <- merge(dat_cut, c, by = c("group","variable"), allow.cartesian = TRUE)
    

    此行然后测试过滤​​器 - 如果您想扩展过滤器逻辑(大于/小于、等于等),您可以扩展此行,并将该逻辑编码回 c

    output <- output[dat_val > c_val]
    

    然后,您想要找到满足过滤器数量等于该组满足的唯一过滤器总数的任何行:

    output[,req_match := uniqueN(c_id), by = .(group)] # number of filters where a condition was met.
    selection <- output[,.N,by = .(id, group, req_match)][N == req_match, id]
    

    如果过滤器没有匹配任何行,它将被排除在此处。

    然后您可以过滤您的初始数据集以获得解决方案:

    dat[id %in% selection]
    
       id group        x        y        z
    1:  3     1 119.4697 217.8550 313.9384
    2: 18     1 117.2930 216.5670 310.4617
    3: 35     1 110.4283 218.6130 312.0904
    4: 50     1 119.2519 214.2517 318.8567
    

    【讨论】:

    • 很好的解释,谢谢!不幸的是,它不会产生正确的结果。重要的是,当一个子集导致一个空集时,它不被应用。这应该适用于每个组。此处,对于不应应用 z 的子集的第 2 组没有结果。
    • @bumblebee 也许我遗漏了一些东西——为什么不应该应用z?有些行 z > 319。
    • 啊,没错,但是x&gt;119y&gt;219 应用后,z&gt;319 的地方就没有了。
    • 我已经重新发布了一个更好的解释:stackoverflow.com/questions/57468728/… 如果你同意这个,如果另一个问题得到解决,我会删除这个帖子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-26
    • 2018-05-19
    • 2019-12-17
    • 2013-08-30
    相关资源
    最近更新 更多