我有一个非常简单的函数,它接受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倍。我有足够的内存可用。
为什么这么慢?我该如何优化呢?
答案 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)