【问题标题】:Format date-time as seasons in R?在R中将日期时间格式化为季节?
【发布时间】:2014-09-16 18:57:58
【问题描述】:

在 R 中,可以将 POSIXlt 日期时间对象格式化为月份:

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

有没有办法对季节或 3 个月组(DJF、MAM、JJA、SON)做同样的事情?这些划分在气候学和生态科学中确实很常见,如果有一种巧妙的方法可以像几个月一样快速格式化它们,那就太好了。显然 DJF 超过 2 年,但出于目的或这个问题,这并不重要 - 只需始终将它们推入任一年,(或者,理想情况下,能够指定它们进入哪一年会很好) .

我将输出用作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”也可能是“2014-DJF”。此外,输出的形式无关紧要 - “2104q4 或 201404 也可以。

【问题讨论】:

  • Here's 相关问答。
  • 如果Q1是DJF等,则转换为"yearmon"类,加一个月转换为"yearqtr"类:library(zoo); format(as.yearqtr(as.yearmon(Sys.time())+1/12))。如果您想要不同的格式,可以使用格式字符串,例如format(as.yearqtr(as.yearmon(Sys.time())+1/12), "%Y-%q")

标签: r datetime datetime-format


【解决方案1】:

as.POSIXlt 返回一个命名列表(这使得它不适合 data.frame 列)。列表列可以单独访问,包括“year”(基于 1900,与默认使用的 1970 不同)和“mon”(基于 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 值的模运算。

【讨论】:

  • 酷,不错。我开始了这个,然后看到你发布的答案然后删除,所以我同时写了我自己的。你的更好,因为它使用了更好的季节名称,但我想它们在功能上或多或少是相同的。我会让投票决定:)
  • 我认为我的不是很明显。模除法和余数总是出错。
  • 我也是,因为 POSIXlt 中月份的内部表示是 0 索引的,而外部表示是 1 索引的。疯狂的。无论如何,我决定使用我的,但这只是因为它允许您将结果保留为日期,这对我的目的很有用。
  • 任何人都可以对所说的模运算有所了解吗?我很感兴趣但很困惑:%/%%% 这里。
  • @KingJulien:请不要向 cmets 发送垃圾邮件。您的问题最终会得到解答。
【解决方案2】:

我喜欢使用查找向量来解决这类问题,例如:

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 名称以重新标记类别。

【讨论】:

    【解决方案3】:

    令 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" 
    

    【讨论】:

    • difftime 基本上是从 12 月变成 1 月,对吧?但这并不准确,因为每个季度的长度不同,而闰年的第一季度的长度也不同。
    • 是的,我刚刚意识到这一点。这不可靠。很快就会删除。
    • 不确定这是否符合我的要求 - 请参阅问题中的编辑示例。
    【解决方案4】:

    这是上面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"
    

    【讨论】:

    • 它对原始版本进行了破坏性修改,然后它并没有真正回答问题,因为您还有几个月的时间。
    • @42-:结果是赛季的第一个月——如果需要的话,用字符串替换“DJF”、“MMA”等的月份并不难。这不适合我。至于数据丢失,将日期转换为季节总是会丢失。如果您在乎,请不要丢弃原始数据。您的解决方案同样有损。
    • 我认为,您应该将该解释编辑为答案,而不是将人们指向 cmets。
    • 我的部分评论来自误读,但你回答了另一部分。我建议你继续弗兰克的建议,我会删除所有我的。
    猜你喜欢
    • 2014-03-01
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 2016-02-26
    • 2021-07-25
    相关资源
    最近更新 更多