2016-09-22 39 views
3

我有一個非常簡單的函數,它接受一個POSIXct日期中提取年,並減去1如果日期是6月1日在日期的矢量上使用sapply:函數非常慢。爲什麼?

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日期的向量,它需要永遠。

sapply(temp$date, DetermineWaterYear) 

此外,我主頻也從長度10000矢量的子集進行sapply至190000使用下面的代碼:

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

這似乎是一個可怕的很多重型機械的東西這可以通過在日期的字符表示上假設一個單獨的'ifelse'語句(假設你的日期都是乾淨的,格式良好的日期)來完成(可能幾乎立即)。 – joran

+1

爲什麼使用sapply?我沒有檢查,但你的功能似乎是矢量化的。 – Roland

+0

@Roland Doh,它是矢量化的,我可以做DetermineWaterYear(temp $日期)來得到我的結果,速度要快得多。儘管如此,仍然很好奇爲什麼薩克利會如此沉迷。 – user278411

回答

0

正如在評論中指出的那樣,將日期向量直接傳遞給函數會更快。此外,ifelse有一噸的開銷,所以用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 
相關問題