r语言 - 当键对数字列和数据从文件读取时,键控数据表的 X[Y] 连接失败



这个很奇怪。不确定我是否遗漏了某些内容,或者它是data.table中的错误还是fread中的错误。

我正在尝试"拉伸"一个缺少一个时间点的时间序列的数据表。从文件中读取此表时,X[Y] 联接将填充缺失行中的 NA,也会填充存在数据点的其他行中的 NA。仅当用于键控的t列包含浮点数而不是整数时,才会发生这种情况。

library(data.table)
# This works fine; empty row at t=0.5
# is filled with NA after join
dt = data.table(id = as.integer(rep(0, 10)), 
t = seq(0.1, 1, 0.1), 
y = 1:10, 
key = "id,t")
dt = dt[!(t == 0.5)]
dtAux = dt[, 
.(seq(min(t), max(t), 0.1)),
by = id]
setkey(dtAux, id, V1)
dt[dtAux]
id   t  y
1:  0 0.1  1
2:  0 0.2  2
3:  0 0.3  3
4:  0 0.4  4
5:  0 0.5 NA
6:  0 0.6  6
7:  0 0.7  7
8:  0 0.8  8
9:  0 0.9  9
10:  0 1.0 10
# This fails; NA’s created in multiple rows
fwrite(dt, "test.csv", row.names = F)
dtFromFile = fread("test.csv")
setkey(dtFromFile, id, t)
dtAux = dtFromFile[, 
.(seq(min(t), max(t), 0.1)),
by = id]
setkey(dtAux, id, V1)
dtFromFile[dtAux]
id   t  y
1:  0 0.1  1
2:  0 0.2  2
3:  0 0.3 NA
4:  0 0.4  4
5:  0 0.5 NA
6:  0 0.6  6
7:  0 0.7 NA
8:  0 0.8  8
9:  0 0.9  9
10:  0 1.0 10

在 3.6.1 上使用data.table1.12.4

进行测试
> sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux bullseye/sid
Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.8.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.8.0
locale:
[1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
[3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
[5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
[7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
[9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     
other attached packages:
[1] data.table_1.12.4
loaded via a namespace (and not attached):
[1] compiler_3.6.1 tools_3.6.1

来自?setNumericRounding

计算机不能使用基数 2 精确表示某些浮点数(例如 0.6(。这 在联接或分组类型为"数字"的列时导致意外行为;即"双倍", 请参阅下面的示例。在不希望的情况下,data.table 允许将此类数据向上舍入为 大约 11 平方英尺,在许多情况下是很多数字。这是通过将 有效数的最后 2 个字节。其他可能的值为 1 字节舍入或不舍入(完整 精度,默认值(。 它是字节而不是位,因为它与用于对数字进行排序的基数排序算法相关联 逐个字节排序。默认舍入为 0 字节时,最多需要 8 次传递。跟 舍入 2 个字节,最多需要 6 次传递(因此可能更快一点(。 对于大数字(整数> 2^31(,我们建议使用 bit64::integer64,即使 默认值为舍入 0 字节(全精度(。

要修复它,您可以在运行代码之前使用以下方法。

setNumericRounding(2)

有关更多示例,请参阅?setNumericRounding,以及舍入到多个并在 data.table 中过滤


编辑:OP询问为什么它在脚本中工作,而不是从文件中读取数据时。这可能是由于ALTREP(请参阅此处的幻灯片9(。

library(data.table) #data.table_1.12.2 R Win x64
dt_seq <- data.table(x = seq(0.1, 0.5, 0.2), v=1:3, key = "x")
dt_c <- data.table(x = c(0.1,0.3,0.5), v=1:3, key = "x")
dtAux_seq = data.table(x=seq(0.1, 0.5, 0.1), key="x")
dtAux_c = data.table(x=c(0.1,0.2,0.3,0.4,0.5), key="x")
fwrite(dt_seq, "test.csv")
dtFromFile <- fread("test.csv", key="x")

测试差异联接:

> dt_seq[dtAux_seq]
x  v
1: 0.1  1
2: 0.2 NA
3: 0.3  2
4: 0.4 NA
5: 0.5  3
> dt_c[dtAux_seq]
x  v
1: 0.1  1
2: 0.2 NA
3: 0.3 NA
4: 0.4 NA
5: 0.5  3
> dtFromFile[dtAux_seq]
x  v
1: 0.1  1
2: 0.2 NA
3: 0.3 NA
4: 0.4 NA
5: 0.5  3

dtAux_c中显式键入值:

> dt_seq[dtAux_c]
x  v
1: 0.1  1
2: 0.2 NA
3: 0.3 NA
4: 0.4 NA
5: 0.5  3
> dt_c[dtAux_c]
x  v
1: 0.1  1
2: 0.2 NA
3: 0.3  2
4: 0.4 NA
5: 0.5  3
> dtFromFile[dtAux_c]
x  v
1: 0.1  1
2: 0.2 NA
3: 0.3  2
4: 0.4 NA
5: 0.5  3

这是由于十进制值上的浮点错误。这不是特定于 R 的问题,而只是计算机处理小数的方式。
阅读更多信息:为什么这些数字不相等?

在连接十进制值时,解决方案是先将它们四舍五入到相关的位数。

dtAux2 = dtFromFile[, 
.( round( seq(min(t), max(t), 0.1), digits = 1 ) ),
by = id]
dt_Aux2
setkey(dtAux2, id, V1)
dtFromFile[dtAux2]
#   id   t  y
#1:  0 0.1  1
#2:  0 0.2  2
#3:  0 0.3  3
#4:  0 0.4  4
#5:  0 0.5 NA
#6:  0 0.6  6
#7:  0 0.7  7
#8:  0 0.8  8
#9:  0 0.9  9
#10:  0 1.0 10

最新更新