R语言按日期条件分块加载大CSV返回空结果,求问题排查
分块加载大型CSV并筛选日期返回空tibble的问题
我是R语言新手,因内存问题需要分块加载大型CSV文件,并筛选日期大于2019-01-01的数据。
示例数据:
| new_patient_id | date |
|---|---|
| 00001526 | 19-Jun-19 |
| 00001527 | 19-Jun-18 |
| 00001528 | 20-Jul-19 |
按预期应返回2条记录,但编写的代码执行后返回空tibble,代码如下:
library(readr) library(dplyr) # Define a function to filter each chunk filter_chunk <- function(chunk, index) { chunk <- chunk %>% mutate(date = as.Date(date, format = "%d-%b-%y")) filtered_chunk <- chunk %>% filter(date >= as.Date("2019-01-01")) return(filtered_chunk) } # Read the file in chunks and filter each chunk chunk_size <- 1000 # Adjust this value based on your memory constraints con <- file("C:/Users/vidnguq/Downloads/r test data.csv", "rb") vinah_contact <- readr::read_csv_chunked(con, callback = filter_chunk, chunk_size = chunk_size, col_types = cols(new_patient_id = col_character(), date = col_character())) # Combine the filtered chunks into a single data frame filtered_vinah_contact <- bind_rows(vinah_contact) # View the filtered data print(filtered_vinah_contact) # Close the file connection close(con)
问题原因及修复方案
1. 日期解析的世纪歧义
as.Date(date, format = "%d-%b-%y") 解析两位年份时,R默认规则可能将19错误解析为1919而非2019,导致所有日期都小于2019-01-01,返回空结果。
修复:使用lubridate包的dmy()函数智能处理年份,或明确指定年份范围:
# 方法1:用lubridate处理日期 library(lubridate) chunk <- chunk %>% mutate(date = dmy(date)) # 方法2:手动拼接年份确保解析为20xx chunk <- chunk %>% mutate(date = as.Date(paste0("20", substr(date, 8,9), "-", substr(date, 4,6), "-", substr(date, 1,2))))
2. 回调函数类型不匹配
read_csv_chunked需要使用特定的回调类型(如DataFrameCallback),直接传入自定义函数会导致返回结果格式异常,bind_rows无法正确合并。
修复:用DataFrameCallback$new()包装过滤函数:
filter_callback <- DataFrameCallback$new(function(chunk, index) { chunk %>% mutate(date = dmy(date)) %>% filter(date >= as.Date("2019-01-01")) })
3. 文件连接模式错误
使用"rb"二进制模式打开文件会干扰read_csv_chunked的文本读取逻辑,导致数据解析异常。
修复:改用默认文本模式打开文件:
con <- file("C:/Users/vidnguq/Downloads/r test data.csv")
完整修复代码
library(readr) library(dplyr) library(lubridate) # 包装过滤逻辑为合法回调 filter_callback <- DataFrameCallback$new(function(chunk, index) { chunk %>% mutate(date = dmy(date)) %>% filter(date >= as.Date("2019-01-01")) }) # 分块读取并过滤 chunk_size <- 1000 con <- file("C:/Users/vidnguq/Downloads/r test data.csv") filtered_vinah_contact <- read_csv_chunked( con, callback = filter_callback, chunk_size = chunk_size, col_types = cols(new_patient_id = col_character(), date = col_character()) ) # 查看结果 print(filtered_vinah_contact) close(con)
内容的提问来源于stack exchange,提问作者Para Perera
相关产品推荐
相关产品推荐

