R jsonlite stream_in失去精度

R jsonlite stream_in losing precision

提问人:qwertzuiop 提问时间:6/1/2022 最后编辑:qwertzuiop 更新时间:6/1/2022 访问量:79

问:

我正在读取带有大 ID 的 ndjson 文件 (~1Gb)。 ID 约为 19 位数字,流式传输时会失去精度。最后 4-5 位数字不同。我怎样才能避免这种情况?谢谢!

library(jsonlite)
data_out <- data.frame(userID = c(1123581321345589000, 3141592653589793000, 2718281828459045000),
                   variable = c("a", "b", "c"))

con_out <- file("test_output.json", open = "wb")
jsonlite::stream_out(data_out, con_out, auto_unbox = T)
close(con_out)

con_in <- file("test_output.json")
data_in <- jsonlite::stream_in(con_in)

> format(data_in$userID, scientific = F)
[1] "1123581321345590016" "3141592653589790208" "2718281828459039744"

编辑:我无法控制输入文件或其格式。如果我在编辑器中打开输入文件,则 ID 是正确的。流式传输时会发生“错误”。

R 精度 jsonlite ndjson

评论

0赞 John Garland 6/1/2022
这些值甚至超出了 64 位浮点值,后者只能存储高达 9,007,199,254,740,992 (2^53) 的连续整数而不会丢失精度。超过这一点,您需要以不同的方式对待这么大的 ID。如果足以进行排序/排列,要么将它们编码为字符串,要么在 CRAN 上探索像 bignum 这样的包。

答:

0赞 Waldi 6/1/2022 #1

您可以转换为:userIDcharacter

library(jsonlite)
data_out <- data.frame(userID = c(1123581321345589000, 3141592653589793000, 2718281828459045000),
                       variable = c("a", "b", "c"))

# Convert to character
data_out$userID <- as.character(data_out$userID)

con_out <- file("test_output.json", open = "wb")
jsonlite::stream_out(data_out, con_out, auto_unbox = T)
#> Complete! Processed total of 3 rows.
close(con_out)

con_in <- file("test_output.json")
data_in <- jsonlite::stream_in(con_in)
#> opening file input connection.
#>  Found 3 records... Imported 3 records. Simplifying...
#> closing file input connection.

identical(data_in,data_out)
#> [1] TRUE

评论

0赞 qwertzuiop 6/1/2022
没错,但不幸的是,我无法控制输入文件或其格式。如果我在编辑器中打开输入文件,则 ID 是正确的。流式传输时会发生“错误”。
0赞 John Garland 6/1/2022
如果读取字符串不能给你提供你需要的功能--如果你检查你对这些标识符的实际需求,它们可能会给你带来,试着看看包bignum或CRAN中较新的gmp中的函数,它们处理任意大的整数和非常高精度的浮点数。
0赞 qwertzuiop 6/1/2022
他们的 ID 不会保存为字符,我无法控制。但是将它们作为字符串阅读会很完美,我只是不知道如何强迫stream_in这样做。我也要看看你推荐的套餐,谢谢!
0赞 John Garland 6/1/2022
您可能会在 tidyverse 中使用像 vroom 这样的 int64 包,它在 R 中提供 true64 位整数。这将使您最多获得 20 个位置 (2^64 = 18,446,744,073,709,551,616)。它应该很好地融入整个整洁的宇宙。
0赞 Waldi 6/1/2022
如果大整数不起作用,直接解析可能是一种解决方案,请参阅 stackoverflow.com/questions/65009389/...