如何为动物园对象上的自定义聚合创建索引

时间:2019-04-02 20:26:38

标签: r zoo

我正在努力寻找一种方法,以将动物园对象汇总到每周结果中,并在每周测量中存在差距。这是要在结果上使用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-04-02创建

对于超长问题的道歉,我知道这不是很好,但是我不知道如何变得更简洁。


我的方法和小功能from this fabulous answer

带来了很多帮助

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

原则上,您设置td_week_strictreg的方法是正确的方法(类似于@ G.Grothendieck对xts所做的工作),但是frequency = 52是不正确的,会使事情搞砸了。 / p>

首先要做的很简单:用frequency剥离as.zoo(),然后得到与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。当您使用每日(而不是年度)时间索引时,增量为7而不是1/52!频率是增量的倒数,即此处的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,从而导致一个空对象。

答案 2 :(得分:0)

我不确定我是否完全理解您要尝试的操作,但是也许首先用零填充缺失的日期会起作用吗?

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