如何通过lubridate中的parse_date_time处理解析多种格式日期时的冲突

omqzjyyz  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(88)

我只是引用了lubridate::parse_date_time()help page,特别是它的select_format参数。但是我无法获得它并为我自己的用例设计我自己的函数。
实际上,我有几种格式的未清理日期向量。为了简单起见,让我们假设,我有mdydmyymdydm的日期。

my_dates <- c("1988-02-03", "1988-15-03", "05-12-2023", "5-27-2022")

lubridate::parse_date_time(my_dates, orders = c("dmy","mdy", "ymd", 'ydm'))

#> [1] "1988-03-02 UTC" "1988-03-15 UTC" "2023-05-12 UTC" "2022-05-27 UTC"

字符串
在输出中,我希望dmy优先于mdyymd优先于ydm。我怎么做?我的输出应该是-

#> [1] "1988-02-03 UTC" "1988-03-15 UTC" "2023-12-05 UTC" "2022-05-27 UTC"

twh00eeo

twh00eeo1#

默认情况下,parse_date_time()基于提供的orders生成一组strptime()日期格式(例如%Y-%m-%d),针对日期的子集训练这些格式,并且根据与训练数据的匹配数量对这些格式进行排名,并基于格式中的标记数量和某些标记的存在应用权重。
要按顺序使用从orders猜测的格式,可以设置train = FALSE

library(lubridate)

my_dates <- c("1988-02-03", "1988-15-03", "05-12-2023", "5-27-2022")
my_orders <- c("dmy","mdy", "ymd", 'ydm')

parse_date_time(my_dates, my_orders, train = FALSE)
[1] "1988-02-03 UTC" "1988-03-15 UTC" "2023-12-05 UTC" "2022-05-27 UTC"

字符串
如果您想按预期使用select_format参数,那么逐步了解发生了什么可能会很有用。
一个函数,用于从一组与x的训练子集匹配的格式中选择实际格式进行解析。它接收一个命名的整数向量并返回所选格式的字符向量。输入向量的名称是与训练集匹配的格式(而不是顺序)。
我们可以看到通过调用guess_formats()猜测的格式:

(guesses <- guess_formats(my_dates, my_orders))

       dOmy        Omdy        Omdy        yOmd        ydOm        ydOm         dmy         mdy         mdy         ymd         ydm 
"%d-%Om-%Y" "%Om-%d-%Y" "%Om-%d-%Y" "%Y-%Om-%d" "%Y-%d-%Om" "%Y-%d-%Om"  "%d-%m-%Y"  "%m-%d-%Y"  "%m-%d-%Y"  "%Y-%m-%d"  "%Y-%d-%m" 
        ydm 
 "%Y-%d-%m"


由于相同的格式可以被猜测多次,因此只需要唯一的格式:

guesses <- unique(guesses)


这些都是针对训练集进行测试的,以查看每个格式返回多少有效转换:

lubridate:::.train_formats(my_dates, guesses, "")

%Om-%d-%Y %Y-%d-%Om  %m-%d-%Y  %Y-%d-%m %d-%Om-%Y %Y-%Om-%d  %d-%m-%Y  %Y-%m-%d 
        2         2         2         2         1         1         1         1


默认情况下,这个命名的vector然后被传递给.select_formats函数,该函数对格式进行加权和排序。您可以检查未导出的函数,以查看应用于某些token的默认权重:

lubridate:::.select_formats
function (trained, drop = FALSE) 
{
    nms <- names(trained)
    score <- nchar(gsub("[^%]", "", nms)) + grepl("%Y", nms, 
        fixed = T) * 1.5 + grepl("%y(?!%)", nms, perl = T) * 
        1.6 + grepl("%[Bb]", nms) * 0.31 + grepl("%Om", nms) * 
        0.3 + grepl("%Op", nms) * 0.3 + grepl("%Ob", nms) * 0.32
    n0 <- trained != 0
    if (drop) {
        score <- score[n0]
        trained <- trained[n0]
    }
    else {
        score[!n0] <- -100
    }
    names(trained)[order(score, trained, decreasing = T)]
}


调用parse_date_time(my_dates, my_orders)时格式的默认优先级为:

lubridate:::.select_formats(lubridate:::.train_formats(my_dates, guesses, locale = ""))
[1] "%Om-%d-%Y" "%Y-%d-%Om" "%d-%Om-%Y" "%Y-%Om-%d" "%m-%d-%Y"  "%Y-%d-%m"  "%d-%m-%Y"  "%Y-%m-%d"


为了改变这一点,我们可以提供一个自定义函数来应用不同的权重,即优先考虑以%d-%m开头的格式,而不是%m-%d%Y-%m开头的格式,而不是%Y-%d

my_select <- function(trained) {
  nms <- names(trained)
  score <- nchar(gsub("[^%]", "", nms)) + grepl("^%d-%O?m", nms) * 2 + grepl("^%Y-%O?m", nms) * 2
  nms[order(score, trained, decreasing = TRUE)]
}


利用这一点,现在的优先事项是:

my_select(lubridate:::.train_formats(my_dates, guesses, locale = ""))
[1] "%d-%Om-%Y" "%Y-%Om-%d" "%d-%m-%Y"  "%Y-%m-%d"  "%Om-%d-%Y" "%Y-%d-%Om" "%m-%d-%Y"  "%Y-%d-%m"

如果我们在parse_date_time()中使用它,我们会得到你想要的结果:

parse_date_time(my_dates, orders, select_formats = my_select)
[1] "1988-02-03 UTC" "1988-03-15 UTC" "2023-12-05 UTC" "2022-05-27 UTC"

值得注意的是,另一种替代方法是使用parse_date_time2并将strptime直接传递给orders

parse_date_time2(my_dates, orders = c("%d-%m-%Y","%m-%d-%Y", "%Y-%m-%d", '%Y-%d-%m'))
[1] "1988-02-03 UTC" "1988-03-15 UTC" "2023-12-05 UTC" "2022-05-27 UTC"

相关问题