在日期向量上使用sapply:函数非常慢。为什么?

时间:2016-09-22 16:31:45

标签: r sapply lubridate

我有一个非常简单的函数,它接受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倍。我有足够的内存可用。

Plot of # of records vs. processing time

为什么这么慢?我该如何优化呢?

1 个答案:

答案 0 :(得分:0)

正如评论中指出的那样,将日期向量直接传递给函数的速度更快。此外,ifelse(month(date)>=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

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

var zigbee = express.Router()
zigbee.get('/zi', function ...)
zigbee.get('/zs', function ...)

app.use('/zigbee', zigbee)