data.table roll=“最近”返回多个结果

data.table roll=“最近”返回多个结果,r,data.table,R,Data.table,我试图使用data.table匹配向量中最接近的十进制值,但遇到了返回多个结果的情况。下面的简化示例返回两个值,0.1818182 0.27273,但对x使用不太精确的值,例如0.0275,则返回单个匹配0.1818182 我假设这个问题与我用于比较的数值的精度有关。可用于最近匹配的十进制精度是否有限制,即是否需要对数据点进行四舍五入?有没有更好的方法来完成最近的匹配?参考Matt的答案,有一种简单的方法可以使用双精度提供的所有15位有效数字来正确选择最近的匹配行。与处理原始值不同,可以将值放大

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


我假设这个问题与我用于比较的数值的精度有关。可用于最近匹配的十进制精度是否有限制,即是否需要对数据点进行四舍五入?有没有更好的方法来完成最近的匹配?

参考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调用中。

是,data.table在连接和分组数字列时自动应用公差。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[Jx,roll=nearest]进行连接时,该x值在公差范围内匹配,并且您得到了它匹配的组,就像在滚动连接中出现匹配值时一样。roll=最近值仅适用于不匹配的值,超出公差范围

data.table认为val第3行和第4行中的值相等。这背后的想法是为了方便,因为大多数时候键值实际上是一个固定的精度,比如价格为1.23美元,或者记录的测量值达到指定的精度1.234567。例如,我们希望加入和分组这样的数字,即使在将它们相乘之后,也不需要自己编写机器精度代码。我们希望避免在数字数据显示时出现混淆,因为它在表中是相等的,但这不是因为位表示中存在非常微小的差异

有关此示例,请参见?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
数据表在公差范围内也是稳定的;i、 e,当您按数字分组时,该组中项目的原始顺序将保持不变

> 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

+1是的,这应该在v1.8.10中起作用。这个讨论是一个很好的时机,因为v1.8.11现在的公差有所不同。现在,它将有效位中最不重要的2个字节舍入到最后16位。因此,扩大规模的伎俩将无法再绕过它。其动机是效率,比特旋转速度很快,但也更符合将机器精度四舍五入到有效数字的原因。但它可以是可选的:默认的2字节舍入,或1字节或0关闭舍入。听起来可以吗?听起来很棒!我想选择禁用舍入功能。如果键列定义了一个固定的数值网格,并且只需要快速的二进制搜索,那么这可能很有用。这样就不需要放弃数值精度。
> 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