我正在阅读一些具有非标准格式日期格式(如 m/d/Y)的 .csv 文件,并使用 fread 函数将日期读取为字符(如 m/d/y),丢失年份的四位数字字符。我尝试使用 colClasses 格式将日期列读取为日期,但它们仍然被读取为具有两个字符年份的字符,并警告日期不是标准的明确格式,请参见下面的示例。
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
当我将 beg_date 列格式化为日期格式时,我得到以下信息:
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"
第二个日期的年份从 1956 年变成 2056 年。第三个日期也有问题,从 1910 年变成 2010 年。csv 文件将这两个日期显示为 7/1/1956 和 9/1/2010。如何使用 colClasses 正确读取日期?
我对 .csv 文件中日期的存储方式感到困惑,但这里有几个选项。
如果日期存储为
mdY
以及全年 (12-25-1910),那么我认为作为字符阅读并使用 lubridate 是一个不错的选择。
set.seed(1)
DT <- data.table::data.table(
orig_beg_date = sample(
seq.Date(
from = as.Date("1900-01-01"),
to = Sys.Date(), by = "month"
),
5
)
)
# format to mdY
DT_mdY <- DT |>
dplyr::mutate(beg_date = format(orig_beg_date, "%m/%d/%Y")) |>
dplyr::select(mdy = beg_date)
# write
data.table::fwrite(DT_mdY, "mdY.csv")
# read in and parse date
x <- data.table::fread("./mdY.csv", colClasses = c(mdy = "character"))
x[, mdy := lubridate::mdy(mdy)]
print(x)
mdy
<Date>
1: 1984-09-01
2: 1956-07-01
3: 1910-09-01
4: 1977-06-01
5: 1939-03-01
如果日期是
mdy
且年份被截断(10年12月25日),我可以复制您的结果,因为年份部分缺少信息。我不确定除了猜测之外它如何知道正确的年份。
# format
DT_mdy <- DT |>
dplyr::mutate(beg_date = format(orig_beg_date, "%m/%d/%y")) |>
dplyr::select(mdy = beg_date)
# write
data.table::fwrite(DT_mdy, "mdy.csv")
x <- data.table::fread("./mdy.csv", colClasses = c(mdy = "character"))
x[, mdy := lubridate::mdy(mdy)]
print(x)
mdy
<Date>
1: 1984-09-01
2: 2056-07-01
3: 2010-09-01
4: 1977-06-01
5: 2039-03-01
如果您知道最大年份,那么您可以事后更改年份部分。
f <- function(x) {
lubridate::year(x) <- lubridate::year(x) - 100
return(x)
}
x[lubridate::year(mdy) >= 2000, mdy := f(mdy)]
print(x)
mdy
<Date>
1: 1984-09-01
2: 1956-07-01
3: 1910-09-01
4: 1977-06-01
5: 1939-03-01
但是,如果您混合使用相同的年份(12-24-10 表示 1910-12-24,12-25-10 表示 2010-12-25),我认为您会运气不好事先不知道哪个是哪个。
从您提到的错误消息来看,日期似乎并非都以相同的格式存储。在这种情况下,如果您事先知道格式,则可以在作为字符读入后使用
lubridate::parse_date_time()
。
date <- c("1910-12-24", "12-24-1910")
lubridate::parse_date_time(date, orders = c("ymd", "mdy"))
[1] "1910-12-24 UTC" "1910-12-24 UTC"
您可能尝试的最后一件事是读取有限数量的行并查看它是否正确解析。可能会帮助您缩小问题范围。
data.table::fread("./mdY.csv", nrows = 2)