R语言bigrquery包写入Google BigQuery丢失小数位问题
问题原因
你调整的全局scipen和digits参数仅对R默认的打印、文本输出生效,bigrquery的bq_table_upload函数在将R数据框序列化后上传到BigQuery时,使用独立的数值转字符串逻辑,不会读取全局参数,会将高精度小数截断为较短的字符串表示,最终传到BQ时就丢失了小数位。而你直接在BQ端执行SQL插入时,数值是直接解析的,不存在R侧序列化截断的问题,所以精度完整。
解决方案
方案1:上传前将数值列转为带足够精度的字符串
上传前把需要保留高精度的数值列格式化为带足够小数位的字符串,BigQuery在导入时会自动将符合数值格式的字符串转为对应NUMERIC类型的值,不会丢失精度:
library(bigrquery) library(dplyr) bq_auth(path = "path_to_credials.json") df <- data.frame(x = c(0.123456789, 1.1, .049384203480324, 2), y = c("dog", "cat", "apple", "pizza")) # 格式化x列为保留15位小数的字符串,避免科学计数法 df <- df %>% mutate(x = sprintf("%.15f", x) %>% trimws()) test_table_name <- "project.ds.table" the_fields <- as_bq_fields(list( bq_field("x", "numeric"), bq_field("y", "string") )) bq_table_upload(x = test_table_name, values = df, fields = the_fields)
方案2:使用Parquet格式中转上传
Parquet是二进制存储格式,原生支持数值精度保留,不会出现字符串序列化导致的截断问题:
library(bigrquery) library(arrow) # 先将数据存为本地parquet文件 write_parquet(df, "temp_upload.parquet") # 直接上传parquet文件到BQ bq_table_upload( x = test_table_name, values = "temp_upload.parquet", fields = the_fields ) # 上传完成后可删除本地临时文件 unlink("temp_upload.parquet")
方案3:改用bq_perform_load批量导入
如果是导入大量数据,可以用bq_perform_load函数,明确指定数值解析的相关参数,避免精度丢失。
内容的提问来源于stack exchange,提问作者Nick Criswell
相关产品推荐
相关产品推荐

