这是对显示的上一个问题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
任何想法将不胜感激。感谢。
答案 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
,因为那没有意义..你可以先为onexpr
按values
到最大>=
进行过滤,然后分钟<=
。
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]