【问题标题】:Robustly parse variably formatted dates in R在 R 中稳健地解析可变格式的日期
【发布时间】:2016-03-23 01:29:16
【问题描述】:

我正在尝试将字符转换为日期。日期具有异构格式,我希望不必单独编码每种日期格式(并指定哪些格式属于哪些元素,例如,grepl)。

这是我的测试数据

test <- c(
  "2012-11-11", "12-5-23", "12/5/86", "2015-12-16 1300", 
  "8/6/92 3:00", "11/6/14 4", "10/31/14 52", 
  "06/15/2014 14:37", "2/10/06", "95-06-26", "82-10-03"
)

期望的结果

as.POSIXct(c("2012-11-11 00:00:00 UTC", "2012-05-23 00:00:00 UTC", "1986-12-05 00:00:00 UTC", "2015-12-16 13:00:00 UTC", "1992-08-06 03:00:00 UTC", "2011-06-14 04:00:00 UTC", "2014-10-31 00:52:00 UTC", "2014-06-15 14:37:00 UTC", "2006-02-10 00:00:00 UTC", "1995-06-26 00:00:00 UTC", "1982-10-03 00:00:00 UTC"), tz="UTC")

我意识到test 中的一些奇怪时间(如 4 或 53)可能无法明确解析,但对于那些我最想确保随机时间不会搞砸日期的人。

这是我的最佳尝试

orders <- paste(rep(c("ymd", "mdy", "Ymd"),each=3), c("HM","H","M"))
lubridate::parse_date_time(test, orders=orders, truncated=2)

[1] "2012-11-11 00:00:00 UTC" "0012-05-23 00:00:00 UTC" "1986-12-05 00:00:00 UTC" "2015-12-16 13:00:00 UTC" "0092-08-06 03:00:00 UTC" "2011-06-14 04:00:00 UTC"
[7] "2014-10-31 00:52:00 UTC" "2014-06-15 14:37:00 UTC" "2006-02-10 00:00:00 UTC" "0095-06-26 00:00:00 UTC" "0082-10-03 00:00:00 UTC"

问题是它在 2 位数年份上弄错了世纪。令人惊讶的是,这很好用:

parse_date_time(test[2], orders=orders[1], truncated=2)
[1] "2012-05-23 UTC"

?parse_date_time中有一条注释:

注意:ymd 系列函数基于 strptime,目前无法解析 %y-%m 格式。

但这不应该在这里适用,因为 1)我有一天,2)当我只有一个没有世纪的年份时,它似乎工作。我认为我的规范中的问题在于它如何与猜测/训练交互。

我认为,Lubridate 几乎可以让这项令人厌烦的任务变得轻松许多。有没有办法获得 lubridate 或任何其他方法来一般解析 test 中的日期?

【问题讨论】:

  • 这根本不可能。 12-1-5
  • @CasimiretHippolyte 有些情况是模棱两可的。但上下文也很重要。我一直在想这个。 test 中的格式并不总是存在于完全相同的数据集中;所以也许我的例子具有误导性。任何给定的数据集可能有 1-3 种格式,但在数据集中,它们通常没有会导致歧义的可变格式。例如,可能有 12-12-12、12-1-23、1923-12-14 合二为一。

标签: regex r date


【解决方案1】:

This answer 只针对错误世纪的特定症状;尽管这是我在测试数据中注意到的唯一问题。我很高兴看到其他人采用稳健转换日期的方法;如果我学到了什么,那就是日期格式总是有更多的惊喜,而且它们通常有解决方案。但是现在,通过严重依赖链接的答案,这是我最好的:

foo <- function(x, orders, year=1940, ...){
  requireNamespace("lubridate", quietly=TRUE)
  x <- lubridate::parse_date_time(x, orders=orders, ...)
  m <- lubridate::year(x) %% 100
  year(x) <- ifelse(m > year %% 100, 1900+m, 2000+m)
  x
}

orders <- paste(rep(c("ymd", "mdy", "Ymd"),each=3), c("HM","H","M"))
foo(test, orders, truncated=2)

 [1] "2012-11-11 00:00:00 UTC" "2012-05-23 00:00:00 UTC" "1986-12-05 00:00:00 UTC" "2015-12-16 13:00:00 UTC" "1992-08-06 03:00:00 UTC" "2011-06-14 04:00:00 UTC"
 [7] "2014-10-31 00:52:00 UTC" "2014-06-15 14:37:00 UTC" "2006-02-10 00:00:00 UTC" "1995-06-26 00:00:00 UTC" "1982-10-03 00:00:00 UTC"

year 参数基本上应该是字符日期向量中出现的最早年份,x

【讨论】:

    猜你喜欢
    • 2013-10-30
    • 2018-05-18
    • 2011-08-18
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 2020-11-16
    • 1970-01-01
    相关资源
    最近更新 更多