data.table roll ="nearest"返回多个结果

use*_*714 7 r data.table

我试图用来data.table匹配向量中最接近的十进制值,但遇到的情况是返回多个结果.下面的简化示例返回两个值,0.1818182 0.2727273但是使用不太精确的值x(例如0.0275)返回单个match(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)]
Run Code Online (Sandbox Code Playgroud)

我假设问题与我用于此比较的数值的精度有关.可以用于最近匹配的小数精度是否有限制(即我需要舍入数据点)?有没有更好的方法来完成这个最接近的比赛?

Mat*_*wle 11

是,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
>
Run Code Online (Sandbox Code Playgroud)

当您使用时dt[J(x), roll="nearest"],该x值匹配在容差范围内,并且您可以像往常一样在滚动连接中出现匹配值时获得与之匹配的组.roll="nearest"仅适用于不匹配的值,超出容差范围.

data.table认为第3行和第4行中的值val相等.这背后的想法是为了方便,因为大多数时候键值实际上是固定的精度,例如价格(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
Run Code Online (Sandbox Code Playgroud)

data.table在公差范围内也是稳定的 ; 也就是说,当您按a分组时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
Run Code Online (Sandbox Code Playgroud)


Geo*_*bel 6

参考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)
Run Code Online (Sandbox Code Playgroud)

现在,执行滚动连接

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

# [1] 0.2727273
Run Code Online (Sandbox Code Playgroud)

产量 - 根据需要 - 单一价值.

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

  • +1是的,应该在v1.8.10中有效.这个讨论实际上是一个很好的时机,因为v1.8.11现在的容差不同.它现在舍去了有效数字的两个最无关紧要的字节(最后16位).所以扩展技巧不会再绕过它了.动机是效率(比特速度很快),但它更符合这样做的原因(机器精度)来舍入到有效数字.它可以是可选的:默认2个字节舍入,或1个字节或0(关闭舍入).听起来不错吗? (2认同)