【问题标题】:Expand quarterly rows to multiple monthly rows将季度行扩展到多个月行
【发布时间】:2021-05-26 05:43:37
【问题描述】:

我有一个数据集,其中有一列引用日期。日期以季度方式书写(即以每 3 个月为 1 个单位)。 一栏表示该日期实际上是按季度还是按月计算的。我只想处理季度类型。

我想将每个季度行扩展到 3 个月行。另一列称为“收益”也会受到影响,应除以“3”(即一个季度的月数)。

例子:

example <- data.frame(quarterly_reports = as.Date(as.character(c(20200331,20200630, 20200930,20201231, 20210131)), "%Y%m%d"),
                      type = c("q","q","q","q","m"),
                      gains = c(18000, 30000, 45000, 60000, 10000))

看起来是这样的:

  quarterly_reports type gains
1        2020-03-31    q 18000
2        2020-06-30    q 30000
3        2020-09-30    q 45000
4        2020-12-31    q 60000
5        2021-01-31    m 10000

我想要的是与此类似的输出(并注意我如何将增益列除以 3):

   quarterly_reports type gains
1         2020-01-31    m  6000
2         2020-02-28    m  6000
3         2020-03-31    m  6000
4         2020-04-30    m 10000
5         2020-05-31    m 10000
6         2020-06-30    m 10000
7         2020-07-31    m 15000
8         2020-08-31    m 15000
9         2020-09-30    m 15000
10        2020-10-31    m 20000
11        2020-11-30    m 20000
12        2020-12-31    m 20000
13        2021-01-31    m 10000

注意:我正在使用data.table,并且我正在尝试使用lubridate 将日期从季度转换为月度。我有大约 300 万行这样的行,所以我正在寻找一些又快又脏的东西。

感谢任何回复。

【问题讨论】:

    标签: r date data.table reshape lubridate


    【解决方案1】:

    更新:根据@Henrik 的建议,这里有一个更有效的替代方案:

    library(lubdridate)
    newexample <- example[type == 'q', .(
      quarterly_reports = quarterly_reports %m-% months(rep(0:2, .N)),
      type = "m",
      gains = gains/3) ]
    setorder(newexample, quarterly_reports)
    newexample
    #     quarterly_reports   type gains
    #                <Date> <char> <num>
    #  1:        2020-01-31      m  6000
    #  2:        2020-02-29      m  6000
    #  3:        2020-03-31      m  6000
    #  4:        2020-04-30      m 10000
    #  5:        2020-05-30      m 10000
    #  6:        2020-06-30      m 10000
    #  7:        2020-07-30      m 15000
    #  8:        2020-08-30      m 15000
    #  9:        2020-09-30      m 15000
    # 10:        2020-10-31      m 20000
    # 11:        2020-11-30      m 20000
    # 12:        2020-12-31      m 20000
    

    (这可能要慢得多,为后代保留。)

    我不知道这会在data.table 的正常引用语义方面为您节省很多效率,因为它必须创建很多行(我认为这不是就地完成的)。不管怎样,

    library(zoo)
    library(data.table)
    setDT(example)
    
    newexample <- example[type == "q",][,rn:=seq_len(nrow(.SD))][, .(
      quarterly_reports = as.Date(seq(as.yearmon(quarterly_reports), length.out = 3, by = -1/12), frac = 1),
      type = rep("m", 3),
      gains = rep(gains, 3) / 3
    ), by = rn ][,rn:=NULL]
    newexample <- rbindlist(list(newexample, example[type != "q",]))
    setorder(newexample, "quarterly_reports")
    newexample[]
    #     quarterly_reports   type gains
    #                <Date> <char> <num>
    #  1:        2020-01-31      m  6000
    #  2:        2020-02-29      m  6000
    #  3:        2020-03-31      m  6000
    #  4:        2020-04-30      m 10000
    #  5:        2020-05-31      m 10000
    #  6:        2020-06-30      m 10000
    #  7:        2020-07-31      m 15000
    #  8:        2020-08-31      m 15000
    #  9:        2020-09-30      m 15000
    # 10:        2020-10-31      m 20000
    # 11:        2020-11-30      m 20000
    # 12:        2020-12-31      m 20000
    # 13:        2021-01-31      m 10000
    

    (@G.Grothendieck 先前的答案https://stackoverflow.com/a/47634838/3358272 建议使用zoo::as.yearmon,以便将日期保持为每个月的最后一天。)

    【讨论】:

    • seq(as.yearmon 可以缩短为lubridate::%m-%as.Date(quarterly_reports) %m-% months(0:2)。不知道速度。 'type' 和 'gain' 将被回收,因此不需要(更明确的)rep。干杯
    • 关于回收的好点,是的,我试图明确(我经常不信任回收,并且与 data.table::fcase 合作强化了这一点),但你是对的,这里不需要。谢谢。 (我不是lubridate pro,很好学习,再次感谢。)
    • 您实际上可以使用months(rep(0:2, .N)) 来避免可怕的by 行。应该对 OP 的 300 万行产生影响。
    猜你喜欢
    • 2014-09-23
    • 1970-01-01
    • 2018-11-16
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    相关资源
    最近更新 更多