---
title: "Aggregating across baskets"
vignette: >
  %\VignetteIndexEntry{Aggregating across baskets}
  %\VignetteEngine{quarto::html}
  %\VignetteEncoding{UTF-8}
knitr:
  opts_chunk: 
    collapse: true
    comment: '#>'
---

Most prices indexes use the same set of weights to aggregate elementary
indexes for several years, periodically updating these weights and
adding or removing elementary aggregates. The general approach to keep
the time series going across baskets is to "chain" the index across
baskets.

Let's start by making some quarterly elementary indexes and weights for
two baskets. Each basket has index values for two years, and there is a
one year overlap between the baskets.

```{r}
library(piar)

set.seed(12345)

# Make quarterly elementary indexes for two baskets with a 1 year overlap.

elementals1 <- matrix(
  runif(5 * 8, 0.8, 1.2),
  nrow = 5,
  dimnames = list(paste0("B", 1:5), NULL)
) |>
  as_index()

elementals2 <- matrix(
  runif(6 * 8, 0.8, 1.2),
  nrow = 6,
  dimnames = list(paste0("B", 1:6), 5:12)
) |>
  as_index()

# Make aggregation weights for basket 1.
#            1
#      |-----+-----|
#      11          12
#  |---+---|   |---+---|
#  B1  B2  B3  B4      B5

weights1 <- data.frame(
  level1 = 1,
  level2 = c(11, 11, 11, 12, 12),
  ea = levels(elementals1),
  weights = runif(5, 100, 200)
)

# Make aggregation weights for basket 2.
#            1
#      |-----+-----|
#      11          12
#  |---+---|   |---+---|
#  B1  B2  B3  B4  B5  B6

weights2 <- data.frame(
  level1 = 1,
  level2 = c(11, 11, 11, 12, 12, 12),
  ea = levels(elementals2),
  weights = runif(6, 100, 200)
)
```

Aggregating the indexes for both baskets involves simply mapping the
usual workflow across both baskets, keeping only the higher-level
indexes because the elementary indexes change across baskets.

```{r}
index <- Map(
  aggregate,
  list(elementals1, elementals2),
  list(weights1, weights2),
  include_ea = FALSE
)
```

There are now several ways to combine these index series to form a
single time series. Assuming that we don't want to revise any index
values from the old basket, the easiest method is to simply ignore the
overlap period and stack the upper-level period-over-period indexes for
the new basket onto the those in the old basket.

```{r}
stack(index[[1]], window(index[[2]], start = "9")) |>
  chain()
```

Alternatively, the index values from the new basket can be chained using
the values in the last period of the first basket as a link factor and
combined with the chained index values from the old basket.

```{r}
link_factor <- chain(index[[1]]) |>
  window(start = end(index[[1]])) |>
  as.numeric()

stack(
  chain(index[[1]]),
  chain(window(index[[2]], start = "9"), link = link_factor)
)
```

The index values for the overlap period can be used to make more complex
link factors when the index series have an annual base period.

```{r}
index <- index |>
  lapply(chain) |>
  lapply(\(x) rebase(x, base = mean(x[, 1:4])))
```

Keeping the base year of the old basket can be done by simply rebasing
the index series for the new basket.

```{r}
link_factor <- window(index[[1]], start = "5") |>
  mean() |>
  as.numeric()

stack(
  index[[1]],
  rebase(window(index[[2]], start = "9"), base = 1 / link_factor)
)
```

Updating the reference year to that of the new basket involves rebasing
the series for both the old basket and the new basket.

```{r}
index[[1]] <- rebase(index[[1]], base = mean(window(index[[1]], start = "5")))

link_factor <- as.numeric(index[[1]][, "8"]) / as.numeric(index[[2]][, "8"])

stack(
  index[[1]],
  rebase(window(index[[2]], start = "9"), base = 1 / link_factor)
)
```
