2014-07-25 92 views
7

在R,它可能格式化POSIXlt日期時間目標爲一個月:在R中將日期時間格式化爲季節?

format(Sys.time(), format='%Y-%m') 

有沒有辦法做到隨季節,或3個月組(DJF,MAM,JJA,SON同樣的事情)?這些部門在氣候學和生態科學領域非常普遍,如果能夠像數月一樣快速地對其進行格式化,那將是非常好的。很明顯,DJF落在兩年以上,但爲了這個目的或這個問題,這並不重要 - 只要一直推到兩年,(或者,理想情況下,能夠指定他們進入哪一年是很好的) 。

我使用輸出作爲by()的索引,所以輸出格式並不重要,只要每年/每個季節都是唯一的。

編輯:示例數據:

dates <- Sys.Date()+seq(1,380, by=35) 
dates <- structure(c(16277, 16312, 16347, 16382, 16417, 16452, 16487, 
        16522, 16557, 16592, 16627), class = "Date") 
dates 
#[1] "2014-07-26" "2014-08-30" "2014-10-04" "2014-11-08" "2014-12-13" 
# "2015-01-17" "2015-02-21" "2015-03-28" "2015-05-02" "2015-06-06" "2015-07-11" 

應導致:

c("2014-JJA", "2014-JJA", "2014-SON", "2014-SON", "2015-DJF", "2015-DJF", 
    "2015-DJF", "2015-MAM", "2015-MAM", "2015-JJA", "2015-JJA") 

但是, 「2015年 - DJF」 S也可能是 「2014 - DJF」。此外,輸出的形式並不重要 - 「2104q4或201404也將被罰款

+1

[這裏](http://stackoverflow.com/questions/9500114/find-which-season-a-particular-date-belongs-to/9501225#9501225)相關的問題和答案。 –

+2

如果Q1是DJF等,那麼將其轉換爲'「yearmon」'類,添加一個月並將其轉換爲'「yearqtr」'class:'library(zoo);格式(as.yearqtr(as.yearmon(Sys.time())+ 1/12))'。如果您需要不同的格式,您可以使用格式字符串,例如'格式(as.yearqtr(as.yearmon(Sys.time())+ 1/12),「%Y-%q」)' –

回答

6

as.POSIXlt返回一個命名列表(這使得它不適合data.frame列)。列表列可以單獨訪問,幷包括「年」(基於1900年,不同於1970年用於默認)和「星期一」(基於0)。看到這份名單中HTE幫助系統最好的地方就是?DateTimeClasses

起初只是四季計算,那麼一年,四季計算

c('DJF', 'MAM', 'JJA', 'SON')[ # select from character vector with numeric vector 
      1+((as.POSIXlt(dates)$mon+1) %/% 3)%%4] 

[1] "JJA" "JJA" "SON" "SON" "DJF" "DJF" "DJF" "MAM" "MAM" "JJA" 
[11] "JJA" 



    paste(1900 + # this is the base year for POSIXlt year numbering 
      as.POSIXlt(dates)$year + 
      1*(as.POSIXlt(dates)$year==12) , # offset needed for December 
      c('DJF', 'MAM', 'JJA', 'SON')[   # indexing from 0-based-mon 
          1+((as.POSIXlt(dates)$mon+1) %/% 3)%%4] 
      , sep="-") 
[1] "2014-JJA" "2014-JJA" "2014-SON" "2014-SON" "2014-DJF" 
[6] "2015-DJF" "2015-DJF" "2015-MAM" "2015-MAM" "2015-JJA" 
[11] "2015-JJA" 

不應該是很難作出這樣的構造格式化函數你的期望。這僅僅是月份和年份的POSIXlt值的模運算。

+0

酷,很好的一個。我開始了這個,然後看到你發佈的答案然後刪除,所以我寫了我自己的同時。你的更好,因爲它使用更好的季節名稱,但我想他們在功能上或多或少是相同的。我會讓選票決定:) – naught101

+0

我不認爲我的是非常明顯的。我用模塊分區和結果總是出錯。 –

+0

我也是這樣做的,因爲POSIXlt中的月份的內部表示是0索引的,而外部表示是1索引的。瘋。無論如何,我決定和我一起走,但只是因爲它可以讓你把結果留作日期,這對我的目的很有用。 – naught101

4

我喜歡使用查找矢量這些各種各樣的問題,如:

x <- as.POSIXlt(
    seq.Date(as.Date("2000-01-01"),as.Date("2002-01-01"),by="2 months") 
) 

例如,如果你。要指定南半球的季節,你可以這樣做:

src <- rep(c("su","au","wi","sp"),each=3)[c(2:12,1)] 

paste(format(x,"%Y-%m"),src[x$mon+1]) 
# [1] "2000-01 su" "2000-03 au" "2000-05 au" "2000-07 wi" "2000-09 sp" 
# [6] "2000-11 sp" "2001-01 su" "2001-03 au" "2001-05 au" "2001-07 wi" 
#[11] "2001-09 sp" "2001-11 sp" "2002-01 su" 

更改src名稱,你認爲合適重新標記類別

2

設Q1是DJF; Q2,MAM等;然後:

seasonal.quarters <- function(x) { 
    x <- as.POSIXlt(x) 
    x$mon <- (x$mon + 1) %% 12 
    quarters(x) 
} 

options(stringsAsFactors=FALSE) 

nonleap.year <- seq(from=as.POSIXct('2013-1-1'), to=as.POSIXct('2014-1-1'), by='day') 
d <- data.frame(ms=months(nonleap.year), qs=seasonal.quarters(nonleap.year)) 
by(d, INDICES=list(d$qs), FUN=function(x) unique(x$ms)) 
# : Q1 
# [1] "January" "February" "December" 
# ------------------------------------- 
# : Q2 
# [1] "March" "April" "May" 
# ------------------------------------- 
# : Q3 
# [1] "June" "July" "August" 
# ------------------------------------- 
# : Q4 
# [1] "September" "October" "November" 

leap.year <- seq(from=as.POSIXct('2016-1-1'), to=as.POSIXct('2017-1-1'), by='day') 
d <- data.frame(ms=months(leap.year), qs=seasonal.quarters(leap.year)) 
by(d, INDICES=list(d$qs), FUN=function(x) unique(x$ms)) 
# : Q1 
# [1] "January" "February" "December" 
# ------------------------------------- 
# : Q2 
# [1] "March" "April" "May" 
# ------------------------------------- 
# : Q3 
# [1] "June" "July" "August" 
# ------------------------------------- 
# : Q4 
# [1] "September" "October" "November" 
+0

difftime基本上將12月份變爲1月份,對不對?但是這不會準確,因爲每個季度都是不同的長度,第一季度在閏年是不同的長度。 – naught101

+0

是的,我剛剛意識到這一點。這不可靠。將很快刪除。 –

+0

@ naught101,已更新。 –

2

這是以上42-'s answer的替代方案。因爲我發佈它的原因,去看看我的評論。

dates_orig <- as.POSIXlt(c("2013-01-01", "2013-02-01", "2013-03-01", "2013-04-01", "2013-05-01", "2013-06-01", "2013-07-01", "2013-08-01", "2013-09-01", "2013-10-01", "2013-11-01", "2013-12-01", "2014-01-01", "2014-02-01", "2014-03-01", "2014-04-01", "2014-05-01", "2014-06-01", "2014-07-01", "2014-08-01", "2014-09-01", "2014-10-01", "2014-11-01", "2014-12-01")) 

format(dates_orig, format='%Y%b') 
[1] "2013Jan" "2013Feb" "2013Mar" "2013Apr" "2013May" "2013Jun" "2013Jul" "2013Aug" "2013Sep" "2013Oct" "2013Nov" "2013Dec" "2014Jan" "2014Feb" "2014Mar" 
[16] "2014Apr" "2014May" "2014Jun" "2014Jul" "2014Aug" "2014Sep" "2014Oct" "2014Nov" "2014Dec" 

dates <- as.POSIXlt(dates_orig) 
# shift Jan and Feb to the previous year 
dates$year[dates$mon < 2] <- dates$year[dates$mon < 2] - 1 
# convert months to seasons (named by first month of season) 
dates$mon <- (((dates$mon - 2) %/% 3) %% 4) * 3 + 2 

format(dates, format='%Y%b') 
[1] "2012Dec" "2012Dec" "2013Mar" "2013Mar" "2013Mar" "2013Jun" "2013Jun" "2013Jun" "2013Sep" "2013Sep" "2013Sep" "2013Dec" "2013Dec" "2013Dec" "2014Mar" 
[16] "2014Mar" "2014Mar" "2014Jun" "2014Jun" "2014Jun" "2014Sep" "2014Sep" "2014Sep" "2014Dec" 
+1

它使用原始的破壞性修改,然後它並沒有真正回答這個問題,因爲你還在等待幾個月。 –

+0

@ 42-:結果在本賽季的第一個月 - 如果需要的話,不需要串接替換「DJF」,「MMA」等的月份。這不適合我。至於數據丟失,將日期轉換爲季節總是*是有損的。如果你在意,那麼不要丟棄原始數據。你的解決方案同樣有損耗。 – naught101

+0

我認爲,您應該將該解釋編輯爲答案,而不是將人指向評論。 – Frank