我有一个有两列的集合。行是值对(a,b)。
require(data.table)
dt<-data.table(a=c(1,11,11,2,7,5,6), b = c(2,9,8,6,5,3,3))
我想为每对值分配最小的数字。 但如果其中一个值再次出现在新行中,则必须再次将其与新对比较并选择历史记录中的最低值。结果必须是这个:
res.dt<-data.table(a=c(1,11,11,2,7,5,6), b = c(2,9,8,6,5,3,3), res=c(1,9,8,1,5,3,1))
a b res
1: 1 2 1
2: 11 9 9
3: 11 8 8
4: 2 6 1
5: 7 5 5
6: 5 3 3
7: 6 3 1
答案 0 :(得分:1)
以不同的方式陈述问题:对于每一行 i ,我们需要迭代地更新{em> j 行中最小值的res
> i 其中(a_i,b_i)和(a_j,b_j)具有非空交集。
我们可以使用data.table
中的non-equi joins(v&gt; = 1.9.8)有效地执行此操作,但由于此功能仅允许单元素比较(>
,{{1} },>=
,==
或<=
),我们需要通过比较(a_i,a_j),(a_i,b_j),(b_i,a_j),(b_i, b_j)分开。 (如果这些对中至少有一个包含相同的元素,则存在交集。)迭代地执行此操作会考虑整个历史记录,并且我们可以在结果收敛时停止:
<
结果:
dt[, `:=`(idx=.I, res=pmin(a,b), prev_res=NA)]
while (dt[, !identical(res, prev_res)]) {
dt[, prev_res:= res]
# Use non-equi joins to update 'res' for intersecting pairs downstream
dt[dt[, .(i.a=a, i.res=res, i=.I)], on=.(a==i.a, idx > i), res:= pmin(res, i.res)]
dt[dt[, .(i.a=a, i.res=res, i=.I)], on=.(b==i.a, idx > i), res:= pmin(res, i.res)]
dt[dt[, .(i.b=b, i.res=res, i=.I)], on=.(a==i.b, idx > i), res:= pmin(res, i.res)]
dt[dt[, .(i.b=b, i.res=res, i=.I)], on=.(b==i.b, idx > i), res:= pmin(res, i.res)]
}