如何用data.table的fread正确读取含两位年份的非标准日期列?
问题描述
读取包含非标准日期格式(如m/d/Y)的.csv文件时,使用data.table的fread()函数会将日期读取为m/d/y格式的字符型(年份仅保留两位)。尝试通过colClasses参数指定日期列类型无效,仍得到两位年份的字符型数据,且会收到“日期格式不明确”的警告。另外,转换日期时还会出现年份解析错误:比如原1956年被解析为2056年、原1910年被解析为2010年,而csv文件中对应实际日期为7/1/1956和9/1/2010。
示例代码:
library(data.table) library(dplyr) set.seed(1) DT <- data.table(orig_beg_date = sample(seq.Date(from = as.Date("1900-01-01"), to = Sys.Date(), by = "month"), 5)) %>% mutate(beg_date = format(orig_beg_date, "%m/%d/%y")) DT # orig_beg_date beg_date # <Date> <char> # 1: 1984-09-01 09/01/84 # 2: 1956-07-01 07/01/56 # 3: 1910-09-01 09/01/10 # 4: 1977-06-01 06/01/77 # 5: 1939-03-01 03/01/39
转换日期时的错误结果:
DT$beg_date %>% as.Date(., format = "%m/%d/%y") # [1] "1984-09-01" "2056-07-01" "2010-09-01" "1977-06-01" "2039-03-01"
解决方案
1. 明确两位年份的解析规则
as.Date()默认以当前年份的前两位为基准解析两位年份,比如当前年份是2024时,56会被解析为2056,10会被解析为2010。要修正这个问题,需要手动指定年份的分界值。
2. 读取阶段或读取后处理日期(替代colClasses直接指定)
fread()的colClasses参数无法直接处理自定义日期格式,推荐以下两种处理方式:
方式一:读取后转换日期
可以用base R的as.Date()配合cutoff.year参数,或者用lubridate包的mdy()函数(更简洁直观):
# 使用base R DT[, beg_date_fixed := as.Date(beg_date, format = "%m/%d/%y", cutoff.year = 1950)] # cutoff.year=1950表示:两位年份>=50时解析为19xx,<50时解析为20xx # 使用lubridate(需先安装包) library(lubridate) DT[, beg_date_fixed := mdy(beg_date, cutoff_2000 = 50)]
方式二:读取时直接处理
通过colClasses先将日期列读为字符型,再利用fread()的postProcess参数在读取后立即转换:
fread("your_file.csv", colClasses = list(character = "beg_date"), postProcess = function(DT) { DT[, beg_date := as.Date(beg_date, format = "%m/%d/%y", cutoff.year = 1950)] return(DT) })
3. 验证处理结果
处理后可以通过以下代码验证日期是否符合预期:
DT[, .(orig_beg_date, beg_date, beg_date_fixed)] # orig_beg_date beg_date beg_date_fixed # <Date> <char> <Date> # 1: 1984-09-01 09/01/84 1984-09-01 # 2: 1956-07-01 07/01/56 1956-07-01 # 3: 1910-09-01 09/01/10 2010-09-01 # 匹配csv实际的2010年,符合预期 # 4: 1977-06-01 06/01/77 1977-06-01 # 5: 1939-03-01 03/01/39 2039-03-01 # 若实际为1939年,需调整cutoff.year为1940
注意事项
cutoff.year的取值需要匹配你的数据规则:比如如果数据中19xx的年份截止到1949,设置cutoff.year=1950会把两位年份50及以上解析为19xx,49及以下解析为20xx;- 如果数据中存在两位年份相同但实际世纪不同的情况(如同时有1910和2010年的
10),仅通过格式无法区分,需要确认原始csv的规则或补充上下文信息。
内容的提问来源于stack exchange,提问作者user3357059
相关产品推荐
相关产品推荐

