All of the examples so far have used a single set of weights to aggregate an index. Although this is by far the most common case, it is not suitable for aggregating a superlative index where there is more than one set of aggregation weights that change every period.
Let’s start by making a chained Paasche index from 6 elementary indexes
over 4 time periods to see how to deal with time-varying aggregation
weights. This is similar to the example of building an index across
multiple basket in vignette("multiple-baskets"), except that the
weights change each period.
library(piar)
set.seed(12345)
# Make 6 elementary indexes over 4 time periods.
elementals <- matrix(c(rep(1, 6), runif(6 * 3, 0.8, 1.2)), nrow = 6) |>
as_index() |>
set_levels(paste0("B", 1:6))
head(elementals)
#> Period-over-period price index for 6 levels over 4 time periods
#> time
#> levels 1 2 3 4
#> B1 1 1.0883616 0.9300382 1.0942740
#> B2 1 1.1503093 1.0036897 0.8004546
#> B3 1 1.1043929 1.0910821 0.9564813
#> B4 1 1.1544498 1.1958948 0.9849979
#> B5 1 0.9825924 0.8138142 0.9552576
#> B6 1 0.8665487 0.8609494 0.9609941
# Make aggregation weights over 4 time periods.
# 1
# |-----+-----|
# 11 12
# |---+---| |---+---|
# B1 B2 B3 B4 B5 B6
weights <- data.frame(
level1 = 1,
level2 = rep(11:12, each = 3),
ea = levels(elementals),
weights = runif(4 * 6, 100, 200),
period = rep(1:4, each = 6)
)
head(weights)
| level1 | level2 | ea | weights | period |
|---|---|---|---|---|
| 1 | 11 | B1 | 117.896 | 1 |
| 1 | 11 | B2 | 195.166 | 1 |
| 1 | 11 | B3 | 145.373 | 1 |
| 1 | 12 | B4 | 132.675 | 1 |
| 1 | 12 | B5 | 196.542 | 1 |
| 1 | 12 | B6 | 170.748 | 1 |
The key tools to deal with time-varying aggregation weights are the
stack() and unstack() functions. stack() appends a later index
series onto an earlier one for the same levels, whereas unstack()
pulls apart an index series for many periods into a collection of
one-period indexes.^[split() can also be used for this.] These functions allow
the aggregation to be done with a map-reduce.
The first step to making a Paasche index is to unstack the elementary indexes into a list of elementary indexes for each period. (Trying to make the elementary indexes period-by-period can be dangerous when there are missing values.)
elementals <- unstack(elementals)
This is followed by making a sequence of aggregation structures for each set of weights.
paasche_pias <- split(
weights[c("level1", "level2", "ea", "weights")],
weights[["period"]]
) |>
lapply(as_aggregation_structure)
Computing the Paasche index for each period is now just a case of
mapping the aggregate() function to each elementary index and
aggregation structure, and then reducing the result with the stack()
function.
paasche <- Map(
aggregate,
elementals,
paasche_pias,
na.rm = TRUE,
include_ea = FALSE,
order = -1
) |>
Reduce(stack, x = _)
paasche
#> Period-over-period price index for 3 levels over 4 time periods
#> time
#> levels 1 2 3 4
#> 1 1 1.0504784 0.9666398 0.9468934
#> 11 1 1.1117341 0.9920294 0.9329698
#> 12 1 0.9898158 0.9447976 0.9647535
Making a chained Fisher index requires two sets of weights: base-period
weights to make the Laspeyres index and current-period weights to make
the Paasche index. As with the Paasche index this can be done with a
map-reduce, except now by passing two aggregation structures to the
aggregate() function instead of one.
laspeyres_pias <- paasche_pias[c(1, 1, 2, 3)]
fisher <- Map(
aggregate,
elementals,
pias = laspeyres_pias,
pias2 = paasche_pias,
na.rm = TRUE,
include_ea = FALSE
) |>
Reduce(stack, x = _)
fisher
#> Period-over-period price index for 3 levels over 4 time periods
#> time
#> levels 1 2 3 4
#> 1 1 1.0509134 0.9783795 0.9600792
#> 11 1 1.1157686 1.0007074 0.9557479
#> 12 1 0.9891911 0.9567760 0.9665552
This gives the same result as calculating the Laspeyres and Paasche indexes individually, and then calculating the Fisher index manually.
laspeyres <- Map(
aggregate,
elementals,
pias = laspeyres_pias,
na.rm = TRUE,
include_ea = FALSE
) |>
Reduce(stack, x = _)
sqrt(as.matrix(laspeyres) * as.matrix(paasche))
| 1 | 2 | 3 | 4 |
|---|---|---|---|
| 1.000 | 1.051 | 0.978 | 0.960 |
| 1.000 | 1.116 | 1.001 | 0.956 |
| 1.000 | 0.989 | 0.957 | 0.967 |