【问题标题】:How to create index for custom aggregation on zoo object如何为动物园对象上的自定义聚合创建索引
【发布时间】:2019-04-02 20:26:38
【问题描述】:

我正在努力寻找一种方法来将动物园对象聚合到每周结果中,而每周测量结果存在差距。这是在结果上使用diff 和其他函数(例如acf)。

library(zoo)
library(xts)

我正在用我的一小部分数据创建一个动物园对象:

time_data <- structure(list(day = structure(c(14246, 14247, 14248, 14249, 14250, 14277, 14278, 14279, 14280, 14281, 14305, 14306, 14307, 14308, 14309), class = "Date"), n_daily = c(10L, 15L, 2L, 15L, 6L, 4L, 6L, 8L, 6L, 1L, 20L, 5L, 8L, 9L, 4L)), row.names = c(NA, -15L), class = c("tbl_df", "tbl", "data.frame"))

z_td <- read.zoo(time_data)

现在,我想按周汇总。我可以使用xts:

td_week_xts <- apply.weekly(z_td, sum)
td_week_xts
#> 2009-01-04 2009-01-06 2009-02-06 2009-03-06 
#>         27         21         25         46

在这里调用diff 不知何故没有意义,因为测量值存在差距。结果应包括“空周”。

diff(td_week_xts)
#> 2009-01-06 2009-02-06 2009-03-06 
#>         -6          4         21

另外,apply.weekly 在您想要定义一周的开始时不是很灵活(至少我没有看到这个选项)。它切断了最后一周。因此我决定尝试用我自己的函数weekly聚合:

weekly <- function(x, week_end = 'sunday') {
  days.of.week <- tolower(weekdays(as.Date(3,"1970-01-01",tz="GMT") + 0:6))
  index = which(days.of.week == week_end)-1
  7 * ceiling(as.numeric(x - index + 4)/7) + zoo::as.Date(index - 4)
}

td_week <- as.zooreg(aggregate(z_td, by = weekly, sum), freq= 52)

td_week
#> 2009-01-04 2009-01-11 2009-02-08 2009-03-08 
#>         27         21         25         46

当然还有差距,但现在实际上包含整周,我还可以定义一周应该从哪一天开始。我现在可以制作一个“严格常规”的动物园对象:

td_week_strictreg <- as.zooreg(merge(td_week, zoo(, seq(min(time(td_week)), max(time(td_week)), 7)), fill = 0))
td_week_strictreg
#> 2009-01-04 2009-01-11 2009-01-18 2009-01-25 2009-02-01 2009-02-08 
#>         27         21          0          0          0         25 
#> 2009-02-15 2009-02-22 2009-03-01 2009-03-08 
#>          0          0          0         46

diff(td_week) 或 diff(td_week_strictreg) 给出相同的结果:

#> Data:
#> integer(0)
#> 
#> Index:
#> Date of length 0

我认为问题在于如何在 zoo/xts 对象中设置时间序列参数,例如xts 对象的频率为 1:

frequency(td_week_xts)
#> [1] 1
frequency(td_week)
#> [1] 52

或者它在于索引:(这里以zoo::as.yearmon 聚合为例,它是一个真正的索引,而不是我的自定义函数......

td_month <- as.zooreg(aggregate(z_td, by = as.yearmon, sum), freq= 12)
str(td_month)
#> 'zooreg' series from Jan 2009 to Mar 2009
#>   Data: int [1:3] 48 25 46
#>   Index:  'yearmon' num [1:3] Jan 2009 Feb 2009 Mar 2009
#>   Frequency: 12

str(td_week)
#> 'zooreg' series from 2009-01-04 to 2009-03-08
#>   Data: int [1:4] 27 21 25 46
#>   Index:  Date[1:4], format: "2009-01-04" "2009-01-11" "2009-02-08" "2009-03-08"
#>   Frequency: 52

由reprex package (v0.2.1) 于 2019 年 4 月 2 日创建

抱歉这个超长的问题,我知道这不是很好,但我不知道如何更简洁。


我的方法和小功能from this fabulous answer得到了很多帮助

【问题讨论】:

    标签: r zoo


    【解决方案1】:

    将td_week 转换为规则间隔的系列,然后使用 diff.xts:

    m <- as.xts(merge(td_week, zoo(, seq(start(td_week), end(td_week), 7)), fill = 0))
    diff(m)
    

    给予:

                 x
    2009-01-04  NA
    2009-01-11  -6
    2009-01-18 -21
    2009-01-25   0
    2009-02-01   0
    2009-02-08  25
    2009-02-15 -25
    2009-02-22   0
    2009-03-01   0
    2009-03-08  46
    

    【讨论】:

    • 谢谢,这行得通。有趣的。顺便说一句 - 你的回答让我意识到我没有从其他答案中适当地引用你的函数。现在将更新 - 也感谢 :)
    • 我又来了。我不明白为什么 diff 对 xts 对象起作用,但对 zooreg 对象不起作用。 Coredata 和 index 在两者中完全相同。为什么 diff 还要处理每月汇总的动物园数据? :( 我猜需要更多阅读。
    【解决方案2】:

    原则上,您设置td_week_strictreg 的方式是正确的方法(类似于@G.Grothendieck 为xts 所做的),但frequency = 52 不正确并且会搞砸。

    首先简单的事情:只需用as.zoo() 去掉frequency,然后得到与xts 相同的结果——除了NA 填充:

    td_week_zoo <- as.zoo(td_week_strictreg)
    class(td_week_zoo)
    ## [1] "zoo"
    diff(td_week_zoo)
    ## 2009-01-11 2009-01-18 2009-01-25 2009-02-01 2009-02-08 2009-02-15 2009-02-22 
    ##         -6        -21          0          0         25        -25          0 
    ## 2009-03-01 2009-03-08 
    ##          0         46 
    

    使用zooreg 代替zoo 没有任何问题,但您需要使用与基础数字时间索引相对应的正确frequency。当您使用 daily(不是 annual)时间索引时,增量是 7 而不是 1/52!频率是 delta 的倒数,即这里的 1/7:

    frequency(td_week_zoo) <- 1/7
    class(td_week_zoo)
    ## [1] "zooreg" "zoo"   
    diff(td_week_zoo)
    ## 2009-01-11 2009-01-18 2009-01-25 2009-02-01 2009-02-08 2009-02-15 2009-02-22 
    ##         -6        -21          0          0         25        -25          0 
    ## 2009-03-01 2009-03-08 
    ##          0         46 
    

    如果您想使用时间索引,其中 1/52 的步长将您带到下周,而 1 的步长将您带到下一年,您需要这样做:

    td_week_zooreg2 <- zooreg(coredata(td_week_zoo), start = 2009, frequency = 52)
    time(td_week_zooreg2)
    ##  [1] 2009.000 2009.019 2009.038 2009.058 2009.077 2009.096 2009.115 2009.135
    ##  [9] 2009.154 2009.173
    diff(td_week_zooreg2)
    ##  2009(2)  2009(3)  2009(4)  2009(5)  2009(6)  2009(7)  2009(8)  2009(9) 
    ##       -6      -21        0        0       25      -25        0        0 
    ## 2009(10) 
    ##       46 
    

    原则上,也可以编写一个专用的yearweek 类,您可以在其中将每周与一周中的特定日期(例如星期日)和相应的日期相关联。我认为没有人写过这样一门课的原因(据我所知)是因为你不会总是在一年中正好有 52 个星期日。

    您的td_week_strictreg 不会导致错误的原因是zooreg 只是检查频率是否可能为52。它是:您可以每 1/52 天(大约 27.7 分钟)再进行一次观察。然后当您使用diff() 时,它想要获取观测值与 27.7 分钟前相应观测值之间的差异。但是由于后者不存在,因此您只会得到被丢弃的 NA,从而导致空对象。

    【讨论】:

    • 这非常有用。多次感谢!!!很想在这里给两个赞成票。不幸的是,我已经接受了另一个答案!
    • 没关系。我认为我的合著者和我自己的综合答案应该提供完整的图片:-)
    【解决方案3】:

    我不确定我是否完全理解你想要做什么,但也许首先用零填充缺失的日期会起作用吗?

    time_all_possibilities = data.frame(
      day = seq(ymd("2009-01-02"), ymd("2009-03-06"), by = "days"))
    
    time_data = merge(time_data, time_all_possibilities, by = "day", all = T)
    time_data$n_daily[is.na(time_data$n_daily)] = 0
    

    【讨论】:

    • 这是一种有趣的方法,但是不幸的是,它不适用于我自定义的聚合数据(但它适用于 xts 对象)。 (顺便说一句,你忘了library(lubridate);)
    猜你喜欢
    • 2013-05-15
    • 2011-12-14
    • 2012-01-23
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-16
    相关资源
    最近更新 更多