【问题标题】:Why are lubridate functions so slow when compared with as.POSIXct?与 as.POSIXct 相比,为什么 lubridate 函数这么慢?
【发布时间】:2012-05-25 15:01:04
【问题描述】:

正如标题所说。为什么 lubridate 函数这么慢?

library(lubridate)
library(microbenchmark)

Dates <- sample(c(dates = format(seq(ISOdate(2010,1,1), by='day', length=365), format='%d-%m-%Y')), 50000, replace = TRUE)

microbenchmark(as.POSIXct(Dates, format = "%d-%b-%Y %H:%M:%S", tz = "GMT"), times = 100)
microbenchmark(dmy(Dates, tz ="GMT"), times = 100)

Unit: milliseconds
expr                                                            min         lq          median      uq          max
1 as.POSIXct(Dates, format = "%d-%b-%Y %H:%M:%S", tz = "GMT")   103.1902    104.3247    108.675     109.2632    149.871
2 dmy(Dates, tz = "GMT")                                        184.4871    194.1504    197.8422    214.3771    268.4911

【问题讨论】:

  • 我会让有更多经验的人加入,但我的猜测是 lubridate 函数旨在处理“幕后”的许多事情,这意味着它对输入进行更多检查/审查尝试给你合理的结果。阅读background docs 与这些情绪相呼应。这是否会导致缓慢,我不确定……但这是我的猜测。同样,plyr 系列也是为了方便而编写的,在某些情况下,与基本函数相比,它的性能可能相对较差……但它很容易使用!
  • @RJ- 如果您的问题中有显示差异的实际代码会更好。 system.time可以用来测量。
  • 注明。很快就会发布。
  • 你只需要使用一个特定的函数而不是通用的。

标签: r lubridate


【解决方案1】:

出于同样的原因,与riding on top of rockets 相比,汽车速度较慢。增加的易用性和安全性使汽车比火箭慢得多,但你不太可能被炸毁,而且更容易启动、转向和制动汽车。然而,在正确的情况下(例如,我需要去月球)火箭是完成这项工作的正确工具。现在,如果有人发明了一种车顶上绑着火箭的汽车,我们就会有所收获。

首先查看 dmy 正在做什么,您会看到速度的差异(顺便说一下,从您的基准来看,我不会说 lubridate 慢得多,因为它们以毫秒为单位):

dmy #在命令行中输入即可:

>dmy
function (..., quiet = FALSE, tz = "UTC") 
{
    dates <- unlist(list(...))
    parse_date(num_to_date(dates), make_format("dmy"), quiet = quiet, 
        tz = tz)
}
<environment: namespace:lubridate>

我马上看到parse_datenum_to_datemake_format。让人想知道所有这些家伙是什么。让我们看看:

parse_date

> parse_date
function (x, formats, quiet = FALSE, seps = find_separator(x), 
    tz = "UTC") 
{
    fmt <- guess_format(head(x, 100), formats, seps, quiet)
    parsed <- as.POSIXct(strptime(x, fmt, tz = tz))
    if (length(x) > 2 & !quiet) 
        message("Using date format ", fmt, ".")
    failed <- sum(is.na(parsed)) - sum(is.na(x))
    if (failed > 0) {
        message(failed, " failed to parse.")
    }
    parsed
}
<environment: namespace:lubridate>

num_to_date

> getAnywhere(num_to_date)
A single object matching ‘num_to_date’ was found
It was found in the following places
  namespace:lubridate
with value

function (x) 
{
    if (is.numeric(x)) {
        x <- as.character(x)
        x <- paste(ifelse(nchar(x)%%2 == 1, "0", ""), x, sep = "")
    }
    x
}
<environment: namespace:lubridate>

make_format

> getAnywhere(make_format)
A single object matching ‘make_format’ was found
It was found in the following places
  namespace:lubridate
with value

function (order) 
{
    order <- strsplit(order, "")[[1]]
    formats <- list(d = "%d", m = c("%m", "%b"), y = c("%y", 
        "%Y"))[order]
    grid <- expand.grid(formats, KEEP.OUT.ATTRS = FALSE, stringsAsFactors = FALSE)
    lapply(1:nrow(grid), function(i) unname(unlist(grid[i, ])))
}
<environment: namespace:lubridate>

哇,我们得到了strsplit-tingexpand-ing.grid-spaste-ingifelse-ingunname-ing 等等,还有一个 Whole Lotta Error Checking Going On(播放 Zep 歌曲)。所以我们这里有一些很好的语法糖。嗯嗯很好吃,但价格和速度是有代价的。

比较一下 as.POSIXct:

getAnywhere(as.POSIXct)  #tells us to use methods to see the business
methods('as.POSIXct')    #tells us all the business
as.POSIXct.date          #what I believe your code is using (I don't use dates though)

as.POSIXct 有更多的内部编码和更少的错误检查所以你必须问我想要轻松和安全还是速度和力量?视工作而定。

【讨论】:

  • +1 很好的答案。另外,您是否注意到parse_date() 本身调用as.POSIXct()?所以最后,dmy() 汽车的引擎盖下有一个as.POSIXct() 引擎。
  • 我认为它实际上是使用as.POSIXct.default来处理一个字符参数(Dates是一个字符向量)。
  • 谁曾否决此回复,这似乎很奇怪,因为其他 24 人认为它有帮助。您能否介绍一下您的选择?
【解决方案2】:

@Tyler 的回答是正确的。以下是更多信息包括让 lubridate 更快的提示 - 来自帮助文件:

" Lubridate 有一个内置的非常快的 POSIX 解析器,从 Simon Urbanek 的 fasttime 包。这个功能还 可选的,可以使用选项激活(lubridate.fasttime = 真的)。 Lubridate 将自动检测 POSIX 字符串并快速使用 解析器而不是默认的 strptime 实用程序。 "

【讨论】:

  • 太棒了!感谢您强调此提示。
猜你喜欢
  • 2012-05-05
  • 2011-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-25
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
相关资源
最近更新 更多