【问题标题】:Large integers in data.table. Grouping results different in 1.9.2 compared to 1.8.10data.table 中的大整数。与 1.8.10 相比,1.9.2 中的分组结果不同
【发布时间】:2014-03-08 18:28:20
【问题描述】:

我最近将 data.table 从 1.8.10 升级到 1.9.2,在跨大整数分组时,我发现两个版本之间存在以下差异。

我是否需要在 1.9.2 中更改设置以使以下两个组语句中的第一个能够像在 1.8.10 中那样工作(我认为 1.8.10 是正确的行为)?

此外,对于以下两个组语句中的第二个,两个包中的结果相同,但这种行为是预期的吗?

1.8.10

>   library(data.table)
data.table 1.8.10  For help type: help("data.table")
>   foo = data.table(i = c(2884199399609098249, 2884199399608934409))
>   lapply(foo, class)
$i
[1] "numeric"

>   foo
                     i
1: 2884199399609098240
2: 2884199399608934400
>   foo[, .N, by=i]
                     i N
1: 2884199399609098240 1
2: 2884199399608934400 1
>   foo = data.table(i = c(9999999999999999999, 9999999999999999998))
>   foo[, .N, by=i]
                      i N
1: 10000000000000000000 2
> 

和 1.9.2

>   library(data.table)
data.table 1.9.2  For help type: help("data.table")
>   foo = data.table(i = c(2884199399609098249, 2884199399608934409))
>   lapply(foo, class)
$i
[1] "numeric"

>   foo
                     i
1: 2884199399609098240
2: 2884199399608934400
>   foo[, .N, by=i]
                     i N
1: 2884199399609098240 2
>   foo = data.table(i = c(9999999999999999999, 9999999999999999998))
>   foo[, .N, by=i]
                      i N
1: 10000000000000000000 2
> 

第一次测试使用的数字(显示 data.table 版本之间的差异)是我的实际数据集中的数字,以及在升级 data.table 后导致我的一些回归测试失败的数字。

我很好奇第二个测试,在我将数字增加另一个数量级之后,如果在 data.table 包的两个版本中都预期忽略最后一个有效数字的微小差异。

我假设这一切都与浮点表示有关。也许我处理这个问题的正确方法是将这些大整数表示为 integer64 或字符?我犹豫是否要使用 integer64,因为我不确定 data.table 和 R 环境是否完全支持它们,例如,我不得不在之前的 data.table 代码中添加它:

options(datatable.integer64="character") # Until integer64 setkey is implemented

也许已经实现了,但无论更改该设置都不会改变这些测试的结果,至少在我的环境中是这样。我认为这是有道理的,因为这些值以数字形式存储在 foo 数据表中。

【问题讨论】:

  • 感谢@Arun 提供的信息。同时,我切换到对具有大整数值的列使用字符,这对我的用例来说很好。

标签: r data.table


【解决方案1】:

是的,v1.8.10 中的结果是正确的行为。我们在 v1.9.2 中改进了舍入方法。这是最好的解释:

Grouping very small numbers (e.g. 1e-28) and 0.0 in data.table v1.8.10 vs v1.9.2

这意味着我们在支持存储在类型 numeric 中的 > 2^31 的整数方面倒退了。现在 v1.9.3(可从 R-Forge 获得)中解决了这个问题,请参阅 NEWS

o bit64::integer64 现在可用于分组和连接,#5369。感谢 James Sams 强调 UPC 和 Clayton Stanley。
提醒:fread() 已经能够检测和读取integer64 有一段时间了。

o 新函数 setNumericRounding() 可用于减少到 1 个字节 或加入时 0 字节舍入 到或分组numeric,#5369 类型的列。请参阅?setNumericRounding 和 NEWS 中的示例 v1.9.2 中的项目。 getNumericRounding() 返回当前设置。

因此,您可以调用setNumericRounding(0) 来关闭所有numeric 列的全局舍入,或者更好地为列使用更合适的类型:bit64::integer64,因为它已受支持。

v1.9.2 的变化是:

o 数字数据仍然像以前一样在容差范围内连接和分组 但不是容差是 sqrt(.Machine$double.eps) == 1.490116e-08 (与 base::all.equal 的默认值相同),有效数字现在四舍五入到最后 2 个字节,apx 11 s.f.这更适合大 (1.23e20) 和小 (1.23e-20) 数字,并且通过简单的位旋转更快。一些函数提供了一个“公差”参数,但它没有被传递,因此已被删除。我们的目标是在未来的版本中添加一个全局选项(例如 2、1 或 0 字节舍入)[DONE]。

?setNumericRounding 中的例子是:

> DT = data.table(a=seq(0,1,by=0.2),b=1:2, key="a")
> DT
     a b
1: 0.0 1
2: 0.2 2
3: 0.4 1
4: 0.6 2
5: 0.8 1
6: 1.0 2
> setNumericRounding(0)   # turn off rounding; i.e. if we didn't round
> DT[.(0.4)]   # works
     a b
1: 0.4 1
> DT[.(0.6)]   # no match!, confusing to users
     a  b      # 0.6 is clearing there in DT, and 0.4 worked ok!
1: 0.6 NA
>     
> setNumericRounding(2)   # restore default
> DT[.(0.6)]   # now works as user expects
     a b
1: 0.6 2
>     
> # using type 'numeric' for integers > 2^31 (typically ids)
> DT = data.table(id = c(1234567890123, 1234567890124, 1234567890125), val=1:3)
> DT[,.N,by=id]   # 1 row (the last digit has been rounded)
             id N
1: 1.234568e+12 3
> setNumericRounding(0)  # turn off rounding
> DT[,.N,by=id]   # 3 rows (the last digit wasn't rounded)
             id N
1: 1.234568e+12 1
2: 1.234568e+12 1
3: 1.234568e+12 1
>  # but, better to use bit64::integer64 for such ids instead of numeric
>  setNumericRounding(2)  # restore default, preferred

【讨论】:

    猜你喜欢
    • 2021-07-19
    • 1970-01-01
    • 2019-08-30
    • 2021-05-17
    • 2018-04-23
    • 2018-03-27
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多