【问题标题】:Using sapply on a vector of dates: Function very slow. Why?在日期向量上使用 sapply:函数非常慢。为什么?
【发布时间】:2016-09-22 16:31:44
【问题描述】:

我有一个非常简单的函数,它接受一个 POSIXct 日期,提取年份,如果日期在 6 月 1 日之前减去 1。

library(lubridate)
DetermineWaterYear <- function(date, 
                               return.interval=FALSE){
  wy <- year(date) + ifelse(month(date)>=6, 0, -1)
  if(return.interval==FALSE){
    return(wy)
  } else {
    interval <- interval(ymd(cat(wy),'06-01', sep=''), ymd(cat(wy+1),'05-31', sep=''))
    return(interval)
  }
}

当我尝试使用 sapply() 在约 190k 日期的向量上执行此功能时,它需要 FOREVER。

sapply(temp$date, DetermineWaterYear)

此外,我使用以下代码对长度从 10000 到 190000 的向量子集执行 sapply 计时:

tempdates <- rep(ymd('1956-01-01'), 190000)


index <- seq(10000,190000,10000)
for(i in 1:length(index)){
  times[i] <- system.time(sapply(tempdates[1:index[i]], DetermineWaterYear))[3]
}

疯狂的是,随着日期向量变长,每条记录的处理时间大大增加……处理 190k 日期所需的时间是 10k 日期所需时间的 238 倍。我有足够的可用内存。

为什么它的行为如此缓慢?如何优化它?

【问题讨论】:

  • 这似乎是一个非常多的重型机器,可以通过在日期的字符表示上使用单个 ifelse 语句来完成(可能几乎是立即)(假设你的日期都很干净,很好格式化日期)。
  • 为什么要使用 sapply?我没有检查,但你的函数似乎是矢量化的。
  • @Roland Doh,它是矢量化的,我可以通过DetermineWaterYear(temp$dates) 更快地得到我的结果。不过,仍然很好奇为什么 sapply 陷入如此多的困境。
  • @Joan 这是很多机器,但DetermineWaterYear() 函数将在一秒钟内扩展为更多选项。

标签: r sapply lubridate


【解决方案1】:

正如 cmets 中所指出的,将日期向量直接传递给函数要快得多。此外,ifelse 有大量开销,因此将ifelse(month(date)&gt;=6, 0, -1) 替换为floor((x/5.6) - (x^2)*0.001) - 1L 会快得多。

DetermineWaterYearNew <- function(date, return.interval=FALSE){
    x <- month(date)
    wy <- year(date) + floor((x/5.6) - (x^2)*0.001) - 1L
    if(return.interval==FALSE){
        return(wy)
    } else {
        interval <- interval(ymd(cat(wy),'06-01', sep=''), ymd(cat(wy+1),'05-31', sep=''))
        return(interval)
    }
}

以下是一些基准:

microbenchmark(NewVectorized=DetermineWaterYearNew(tempdates[1:1000]),
               OldVectorized=DetermineWaterYear(tempdates[1:1000]),
               NonVectorized=sapply(tempdates[1:1000],DetermineWaterYear))
Unit: microseconds
         expr       min         lq       mean     median         uq       max neval
NewVectorized   341.954   364.1215   418.7311   395.7300   460.7955   602.627   100
OldVectorized   417.077   437.3970   496.0585   462.8485   545.1555   802.954   100
NonVectorized 42601.719 45148.3070 46452.6843 45902.4100 47341.2415 62898.476   100

仅比较我们拥有的全部日期的矢量化解决方案:

microbenchmark(NewVectorized=DetermineWaterYearNew(tempdates[1:190000]),
               OldVectorized=DetermineWaterYear(tempdates[1:190000]))
Unit: milliseconds
         expr      min       lq     mean   median       uq      max neval
NewVectorized 26.30660 27.26575 28.97715 27.84169 29.19391 102.1697   100
OldVectorized 38.98637 40.78153 44.07461 42.55287 43.77947 114.9616   100

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-28
    • 1970-01-01
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多