【问题标题】:Fastest way to convert strings to dates in R在 R 中将字符串转换为日期的最快方法
【发布时间】:2019-09-20 16:23:58
【问题描述】:

我想在R 中以字符串形式(例如:“09/20/2019”)转换大约 1 亿个日期。

在做

a = "09/20/2019"       
a <- as.Date(a, "%m/%d/%Y")

似乎有点慢。有没有更快的方法来实现这种转换?

(尝试了fasttime 包,但它需要以下顺序:year, month, day... 因此原始字符串需要进一步操作)

【问题讨论】:

    标签: r fasttime


    【解决方案1】:

    对于此示例数据,使用查找表方法 (1) 比 as.Date 快 38 倍。对于这个示例数据,方法 (2) 仍然快 18 倍,如果您没有生成d 的好方法,则更方便。当然,您的数据细节会影响实际实现的加速。

    # test data
    set.seed(123)
    d <- format(as.Date("2000-01-01") + 1:100, "%m/%d/%Y")
    dd <- sample(d, 1000000, replace = TRUE)
    
    # 1 - lookup table
    system.time(as.Date(d, "%m/%d/%Y")[match(dd, d)])
    ##    user  system elapsed 
    ##    0.06    0.02    0.07 
    
    # 2 - table lookup generating u on the fly instead of d
    system.time({u <- unique(dd); as.Date(u, "%m/%d/%Y")[match(dd, u)] })
    ## user  system elapsed 
    ## 0.13    0.03    0.15 
    
    # 3 - as.Date
    system.time(as.Date(dd, "%m/%d/%Y"))
    ##    user  system elapsed 
    ##    2.61    0.07    2.67 
    

    【讨论】:

    • 带有dd的查找表提前排序也应该节省一点时间
    【解决方案2】:

    使用润滑

    
    library(lubridate)
    a = "09/20/2019"
    mdy(a)
    

    【讨论】:

    • @joran 应该够快了,我在 100 万个随机日期上测试了mdy,只用了 0.22 秒。
    • @joran 需要 6 层才能到达那里,但我认为最终它使用 lubridate:::C_parse_dt 可能比使用通用 strptimeas.Date 更快。我对 C 方面的了解还不够,无法更根本地发表评论
    【解决方案3】:

    既然你提到了fasttime,我就好奇地想用其他一些常见的选项来测试它。它需要年月日格式的日期,但您可以使用一些正则表达式来做到这一点。

    我对一组较小但仍然很麻烦的日期进行了基准测试。我在一台使用了一年的 MacBook Pro 上运行了很多其他的东西,并且还在 100 万次约会中进行了 100 次试验,并且在我吃完三明治之前完成了所有 3 种方法。

    set.seed(9)
    days <- sample(1:30, 1e6, replace = TRUE)
    date_str <- sprintf("09/%02d/2019", days)
    
    # as.Date(date_str, format = "%m/%d/%Y")
    # lubridate::mdy(date_str)
    # fasttime::fastPOSIXct(gsub("^(\\d{2})/(\\d{2})/(\\d{4})", "\\3-\\1-\\2", date_str))
    
    bench <- microbenchmark::microbenchmark(
      list = list(
        base = as.Date(date_str, format = "%m/%d/%Y"),
        lubr = lubridate::mdy(date_str),
        fast = fasttime::fastPOSIXct(gsub("^(\\d{2})/(\\d{2})/(\\d{4})", "\\3-\\1-\\2", date_str))
      )
    )
    
    bench
    #> Unit: nanoseconds
    #>  expr min lq mean median uq max neval cld
    #>  base   3  5 7.02      5  6 180   100   a
    #>  lubr   4  5 6.91      6  6 148   100   a
    #>  fast   4  5 8.77      5  6 332   100   a
    

    基于平均值和最低最大值,lubridate::mdy 运行速度最快,无需重新格式化或指定格式字符串。基于中位数,基本 as.Date 运行最快,但需要您设置格式化字符串(不是什么大问题),或 fasttime 但使用正则表达式规定。随心所欲。

    我还注意到fasttime 转换为 POSIX,因此由于没有设置时间元素,因此将其添加到其中 - 删除它可能会成为另一个耗时的步骤。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-14
      • 2014-06-08
      • 1970-01-01
      • 2019-01-08
      • 2023-03-26
      • 2023-03-21
      • 2012-10-05
      相关资源
      最近更新 更多