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

问题描述 投票:0回答:1

我刚刚提到了lubridate::parse_date_time()

帮助页面
,特别是它的
select_format
论点。但我无法获得它并为自己的用例设计自己的功能。

实际上,我有一些格式的未清理日期向量。为了简单起见,让我们假设,我有

mdy
dmy
ymd
ydm
格式的日期。

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
优先于
mdy
,并且
ymd
优先于
ydm
。我该怎么做?我的输出应该是-

#> [1] "1988-02-03 UTC" "1988-03-15 UTC" "2023-12-05 UTC" "2022-05-27 UTC"
r parsing lubridate
1个回答
2
投票

parse_date_time()
默认情况下会根据提供的
strptime()
生成一组
%Y-%m-%d
日期格式(例如
orders
),针对日期子集对这些格式进行训练,并且这些格式根据训练的匹配数进行排名根据格式中的标记数量和某些标记的存在应用权重的数据。

要依次使用从

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 

默认情况下,此命名向量会传递给

.select_formats
函数,该函数对格式进行加权和排序。您可以检查未导出的函数以查看应用于某些令牌的默认权重:

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"
© www.soinside.com 2019 - 2024. All rights reserved.