1

我正在使用 fable 包来获取一组分层时间序列的预测。我想指定一个层次结构,它在所有节点上都没有相同的深度。

现实例子:

  • 时间序列 B1 和 B2 相加为时间序列 M1。
  • 时间序列 M1 和 M2 相加为时间序列 T,它位于层次结构的顶部。
  • 时间序列 M2 不是一组时间序列的总和;这是它自己的时间序列。

创建一个小的随机数据集,tsibble格式为:


library(dplyr)
library(tsibble)
library(fable)

set.seed(1)
B1 <- rnorm(12, mean = 5) + (1:12)
B2 <- rnorm(12, mean = 5)
M2 <- rnorm(12, mean = 25)

ts_data <- tibble(value = c(B1, B2, M2), 
                  month = rep(yearmonth(paste("2020", 1:12, sep="-")), 3), 
                  B = c(rep("B1", 12), rep("B2", 12), rep("B3", 12)), 
                  M = c(rep("M1", 24), rep("M2", 12))) %>%
  as_tsibble(key = c("B", "M"), index = month)

在 3 个时间序列中的每一个上估计单独的 ARIMA 模型,聚合和预测:

fcsts <- ts_data %>%
  # Specify hierarchy
  aggregate_key(M / B, value = sum(value)) %>%
  # Fit models
  model(arima = ARIMA(value)) %>%
  # Set up reconciliation
  mutate(mint = min_trace(arima)) %>%
  # Produce the forecasts
  forecast(h = 1)

我之所以担心结果可能是错误的,是因为我可以创建一个病态的例子,即使没有实际的聚合,对账给出的置信区间也更小:

病理例子:

  • 时间序列 B3 是 M2 的孩子,M2 是 T 的孩子。

我通过对前一个数据集进行子集来为此示例创建一个数据集:

ts_data_2 <- ts_data %>% 
  filter(B == "B3")

再次估计单独的 ARIMA 模型、聚合和预测:

fcsts_2 <- ts_data_2 %>%
  # Specify hierarchy
  aggregate_key(M / B, value = sum(value)) %>%
  # Fit models
  model(arima = ARIMA(value)) %>%
  # Set up reconciliation
  mutate(mint = min_trace(arima)) %>%
  # Produce the forecasts
  forecast(h = 6)

结果如下:

> fcsts_2
# A fable: 6 x 6 [1M]
# Key:     M, B, .model [6]
  M            B            .model    month value .distribution
  <chr>        <chr>        <chr>     <mth> <dbl> <dist>       
1 M2           B3           arima  2021 Jan  24.9 N(25, 0.63)  
2 M2           <aggregated> arima  2021 Jan  24.9 N(25, 0.63)  
3 <aggregated> <aggregated> arima  2021 Jan  24.9 N(25, 0.63)  
4 M2           B3           mint   2021 Jan  24.9 N(25, 0.21)  
5 M2           <aggregated> mint   2021 Jan  24.9 N(25, 0.21)  
6 <aggregated> <aggregated> mint   2021 Jan  24.9 N(25, 0.21)  

方差从原始 ARIMA 模型中的 0.63 减小到 0.21,即使没有实际聚合。当然,这是一个示例,根本不应该使用对帐,但是这里方差减小的事实让我担心在现实示例中对帐无法正常工作。

有没有办法在实际示例中指定模型以避免从 B3 聚合到 M2?(我尝试在 B 列中使用 NA 而不是级别“B3”,但这不起作用。)

4

2 回答 2

4

这里的问题是,协调是基于对误差协方差矩阵的估计,并且默认设置使用对角矩阵,当存在退化的层次结构时,这会导致严重低估。

当您使用该mint_shrink选项时,会出现更好的结果(尽管仍有一些偏差):

library(dplyr)
library(tsibble)
library(fable)

set.seed(1)
B1 <- rnorm(12, mean = 5) + (1:12) 
B2 <- rnorm(12, mean = 5) 
M2 <- rnorm(12, mean = 25) 

ts_data <- tibble(value = c(B1, B2, M2),  
                  month = rep(yearmonth(paste("2020", 1:12, sep="-")), 3),  
                  B = c(rep("B1", 12), rep("B2", 12), rep("B3", 12)),  
                  M = c(rep("M1", 24), rep("M2", 12))) %>% 
  as_tsibble(key = c("B", "M"), index = month) 
ts_data_2 <- ts_data %>%  
  filter(B == "B3") 
ts_data_2 %>% 
  # Specify hierarchy 
  aggregate_key(M / B, value = sum(value)) %>% 
  # Fit models 
  model(arima = ARIMA(value)) %>% 
  # Set up reconciliation 
  mutate(mint = min_trace(arima, method="mint_shrink")) %>% 
  # Produce the forecasts 
  forecast(h = 6)
#> # A fable: 36 x 6 [1M]
#> # Key:     M, B, .model [6]
#>    M     B     .model    month       value .mean
#>    <chr> <chr> <chr>     <mth>      <dist> <dbl>
#>  1 M2    B3    arima  2021 Jan N(25, 0.63)  24.9
#>  2 M2    B3    arima  2021 Feb N(25, 0.63)  24.9
#>  3 M2    B3    arima  2021 Mar N(25, 0.63)  24.9
#>  4 M2    B3    arima  2021 Apr N(25, 0.63)  24.9
#>  5 M2    B3    arima  2021 May N(25, 0.63)  24.9
#>  6 M2    B3    arima  2021 Jun N(25, 0.63)  24.9
#>  7 M2    B3    mint   2021 Jan N(25, 0.56)  24.9
#>  8 M2    B3    mint   2021 Feb N(25, 0.56)  24.9
#>  9 M2    B3    mint   2021 Mar N(25, 0.56)  24.9
#> 10 M2    B3    mint   2021 Apr N(25, 0.56)  24.9
#> # … with 26 more rows

reprex 包(v0.3.0)于 2020 年 9 月 23 日创建

于 2020-09-23T01:12:16.693 回答
2

以编程方式,fable 允许您删除您不想要的聚合/分解。要删除 B3 级别,您可以使用:

library(fpp3)
B1 <- rnorm(12, mean = 5) + (1:12)
B2 <- rnorm(12, mean = 5)
M2 <- rnorm(12, mean = 25)

ts_data <- tibble(value = c(B1, B2, M2), 
                  month = rep(yearmonth(paste("2020", 1:12, sep="-")), 3), 
                  B = c(rep("B1", 12), rep("B2", 12), rep("B3", 12)), 
                  M = c(rep("M1", 24), rep("M2", 12))) %>%
  as_tsibble(key = c("B", "M"), index = month)

ts_data %>%
  # Specify hierarchy
  aggregate_key(M / B, value = sum(value)) %>% 
  # Remove redundant nodes from hierarchy (#226)
  filter(!(B == "B3")) %>% 
  # Fit models
  model(arima = ARIMA(value)) %>%
  # Set up reconciliation
  mutate(mint = min_trace(arima)) %>%
  # Produce the forecasts
  forecast(h = 1)
#> # A fable: 10 x 6 [1M]
#> # Key:     M, B, .model [10]
#>    M            B            .model    month        value .mean
#>    <chr>        <chr>        <chr>     <mth>       <dist> <dbl>
#>  1 M1           B1           arima  2021 Jan   N(19, 1.9) 18.5 
#>  2 M1           B1           mint   2021 Jan   N(18, 1.2) 17.6 
#>  3 M1           B2           arima  2021 Jan    N(4.9, 1)  4.86
#>  4 M1           B2           mint   2021 Jan N(4.3, 0.81)  4.26
#>  5 M1           <aggregated> arima  2021 Jan   N(20, 3.6) 20.4 
#>  6 M1           <aggregated> mint   2021 Jan   N(22, 1.2) 21.9 
#>  7 M2           <aggregated> arima  2021 Jan  N(25, 0.62) 24.8 
#>  8 M2           <aggregated> mint   2021 Jan  N(25, 0.56) 24.7 
#>  9 <aggregated> <aggregated> arima  2021 Jan     N(46, 4) 45.8 
#> 10 <aggregated> <aggregated> mint   2021 Jan   N(47, 1.4) 46.6

reprex 包(v0.3.0)于 2020 年 9 月 23 日创建

您尝试使用NA代替 B3 实际上接近我在下一个版本中添加的内容,以更好地支持不平衡的层次结构。我将导出agg_vec()以允许您创建自定义<aggregated>值,然后可以将其传递到aggregate_key(). 我还希望添加一个功能来aggregate_key()检测冗余节点,并可能删除它们(https://github.com/tidyverts/fabletools/issues/226)。

于 2020-09-23T02:22:16.517 回答