r语言 - data.table roll= "nearest"返回多个结果



我试图使用data.table来匹配向量中最接近的十进制值,但遇到了返回多个结果的情况。下面的简化示例返回两个值0.1818182 0.2727273,但使用不太精确的值x(例如0.0275)返回单个匹配(0.1818182)。

x = 0.0275016249293408
dt = data.table(rnk = c(0, 0.0909090909090909, 
0.181818181818182, 0.272727272727273),
val = c(0.0233775088495975, 0.0270831481152598, 
0.0275016216267234, 0.0275016249293408),
key="val")
dt[J(x), roll="nearest"][, ifelse(is.na(val), NA_real_, rnk)]

我假设这个问题与我用于比较的数值的精度有关。可用于最接近匹配的小数精度是否有限制(即,我需要四舍五入数据点吗)?有没有更好的方法来完成这场势均力敌的比赛?

是的,data.table在连接和分组numeric列时自动应用公差。v1.8.10中的公差为sqrt(.Machine$double.eps) == 1.490116e-08。这直接来自?base::all.equal

为了说明,考虑分组:

> dt
rnk        val
1: 0.00000000 0.02337751
2: 0.09090909 0.02708315
3: 0.18181818 0.02750162
4: 0.27272727 0.02750162
> dt[,.N,by=val]
val N
1: 0.02337751 1
2: 0.02708315 1
3: 0.02750162 2    # one group, size two
>

当您使用dt[J(x), roll="nearest"]联接时,x的值在公差范围内匹配,并且您得到了它匹配的组,就像在滚动联接中出现匹配值时一样。roll="nearest"仅适用于不匹配、超出公差范围的值。

CCD_ 13认为CCD_ 14的第3行和第4行中的值相等。这背后的想法是为了方便,因为大多数时间键值实际上都是固定的精度,如价格(1.23美元)或指定精度的记录测量值(1.234567)。例如,即使在相乘后,我们也希望加入和分组这样的numerics,而无需自己为机器精度进行编码。当numeric数据在表中显示为相等,但不是由于位表示的微小差异时,我们希望避免混淆。

参见?unique.data.table了解此示例:

DT = data.table(a=tan(pi*(1/4 + 1:10)), b=rep(1,10))   # example from ?all.equal
length(unique(DT$a))         # 10 strictly unique floating point values
all.equal(DT$a,rep(1,10))    # TRUE, all within tolerance of 1.0
DT[,which.min(a)]            # row 10, the strictly smallest floating point value
identical(unique(DT),DT[1])  # TRUE, stable within tolerance
identical(unique(DT),DT[10]) # FALSE

CCD_ 18在耐受范围内也稳定;即,当您按numeric分组时,该组中项目的原始顺序将照常保持。

> dt$val[3] < dt$val[4]   # in your example data, 3 is strictly less than 4
[1] TRUE
> dt[, row:=1:4]  # add a row number to illustrate
> dt[, list(.N, list(row)), by=val]
val N  V2
1: 0.02337751 1   1
2: 0.02708315 1   2
3: 0.02750162 2 3,4
> dt[3:4, val:=rev(val)]   # swap the two values around
> dt$val[3] > dt$val[4]
[1] TRUE
> dt[, list(.N, list(row)), by=val]
val N  V2
1: 0.02337751 1   1
2: 0.02708315 1   2
3: 0.02750162 2 3,4    # same result, consistent. stable within tolerance

参考Matt的答案,有一种简单的方法可以使用双精度提供的所有15位有效数字,以便正确选择最接近的匹配行。不用处理原始值,可以将值放大,以确保15个有效数字位于10^(-8)水平以上。这可以通过以下方式实现:

orig_vals <- dt[,val]
scale_fact <- max(10^(trunc(log10(abs(orig_vals)))+8))
scaled_vals <- orig_vals * scale_fact
dt[,scaled_val:=scaled_vals]
setkey(dt,scaled_val)

现在,执行滚动连接

scaled_x <- x*scale_fact
dt[J(scaled_x), roll="nearest"][, ifelse(is.na(val), NA_real_, rnk)]
# [1] 0.2727273

根据需要生成单个值

如果在两个相同键值的情况下也只应选择一行,则可以将mult="first"参数添加到上述data.table调用中。

最新更新