计算每个条件通过和失败的观察结果

时间:2017-12-01 15:38:04

标签: r data.table

这是对显示的上一个问题here的后续跟进。

我的数据类似于以下内容:

set.seed(1)
dt <- data.table(ID=1:10, Status=c(rep("OUT",2),rep("IN",2),"ON",rep("OUT",2),rep("IN",2),"ON"), 
                 t1=round(rnorm(10),1), t2=round(rnorm(10),1), t3=round(rnorm(10),1), 
                 t4=round(rnorm(10),1), t5=round(rnorm(10),1), t6=round(rnorm(10),1),
                 t7=round(rnorm(10),1),t8=round(rnorm(10),1))

    ID Status   t1   t2   t3   t4   t5   t6   t7   t8
 1:  1    OUT -0.6  1.5  0.9  1.4 -0.2  0.4  2.4  0.5
 2:  2    OUT  0.2  0.4  0.8 -0.1 -0.3 -0.6  0.0 -0.7
 3:  3     IN -0.8 -0.6  0.1  0.4  0.7  0.3  0.7  0.6
 4:  4     IN  1.6 -2.2 -2.0 -0.1  0.6 -1.1  0.0 -0.9
 5:  5     ON  0.3  1.1  0.6 -1.4 -0.7  1.4 -0.7 -1.3
 6:  6    OUT -0.8  0.0 -0.1 -0.4 -0.7  2.0  0.2  0.3
 7:  7    OUT  0.5  0.0 -0.2 -0.4  0.4 -0.4 -1.8 -0.4
 8:  8     IN  0.7  0.9 -1.5 -0.1  0.8 -1.0  1.5  0.0
 9:  9     IN  0.6  0.8 -0.5  1.1 -0.1  0.6  0.2  0.1
10: 10     ON -0.3  0.6  0.4  0.8  0.9 -0.1  2.2 -0.6

我将约束应用于从{csv:

读入的dt
dt_constraints <- data.table(columns=c("t1","t3","t7","t8"), operator=c(rep(">=",2),rep("<=",2)), 
                             values=c(-.6,-.5,2.4,.5))

    columns operator    values
1   t1       >=         -0.6
2   t3       >=         -0.5
3   t7       <=          2.4
4   t8       <=          0.5

@akrun提供了一个非常有效的解决方案:

dt[eval(parse(text=do.call(paste, c(dt_constraints, collapse= ' & '))))]

我还需要两个额外的信息:通过每个约束的观察数量和每个约束失败的观察数量。输出可能如下所示:

    columns operator    values  obs_pass  obs_fail
1   t1       >=         -0.6       8         2
2   t3       >=         -0.5       8         2
3   t7       <=          2.4       10        0
4   t8       <=          0.5       9         1

任何想法将不胜感激。感谢。

1 个答案:

答案 0 :(得分:3)

您可以构造on=表达式并为每一行执行连接:

dt_constraints[, onexpr := sprintf("%s%sv", columns, operator)]

dt_constraints[, n_pass := dt[.(v = values), on=onexpr, .N, by=.EACHI]$N, by=onexpr]
dt_constraints[, n_fail := nrow(dt) - n_pass ]

by=.EACHI应该允许您使用具有多个不同onexpr的相同values,但我想有更好的方法可以做到这一点。如果onexpr是唯一的,那就是......

dt_constraints[, n_pass := dt[.(v = values), on=onexpr, .N], by=onexpr]
dt_constraints[, n_fail := nrow(dt) - n_pass ]

使用此方法立即过滤所有约束:*

n_grp = nrow(dt_constraints)
w = seq_len(nrow(dt))
dt[dt_constraints[, {
  w <- w[dt[w][.(v = values), on=onexpr, which=TRUE]]
  if (.GRP == n_grp) w
}, by=onexpr]$V1]

   ID Status   t1  t2   t3   t4   t5   t6   t7   t8
1:  1    OUT -0.6 1.5  0.9  1.4 -0.2  0.4  2.4  0.5
2:  2    OUT  0.2 0.4  0.8 -0.1 -0.3 -0.6  0.0 -0.7
3:  5     ON  0.3 1.1  0.6 -1.4 -0.7  1.4 -0.7 -1.3
4:  7    OUT  0.5 0.0 -0.2 -0.4  0.4 -0.4 -1.8 -0.4
5:  9     IN  0.6 0.8 -0.5  1.1 -0.1  0.6  0.2  0.1
6: 10     ON -0.3 0.6  0.4  0.8  0.9 -0.1  2.2 -0.6

这就像循环迭代一样,只检查那些先前约束所持有的行(w)。

*假设没有重复onexpr,因为那没有意义..你可以先为onexprvalues到最大>=进行过滤,然后分钟<=

OP的后续问题:

  

如何更改代码以执行以下操作:(1)为第一个约束提供通过/失败计数; (2)使用来自第一个约束的传递子集的数据,给出第二个约束的传递/失败计数; (3)使用来自第二个约束的传递子集的数据,给出第三个约束的传递/失败计数等。

# iteratively count pass/fail
w = seq_len(nrow(dt))
dt_constraints[, {
  w0 <- w
  w <- w[dt[w][.(v = values), on=onexpr, which=TRUE]]
  .(n_pass = length(w), n_fail = length(w0) - length(w))
}, by=onexpr]