The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Superlative aggregation

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.

Aggregating a Paasche index

Let’s start by making a chained Paasche index from 6 elemental 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 elemental 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 
##    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      1     11 B1 117.8964      1
## 2      1     11 B2 195.1659      1
## 3      1     11 B3 145.3728      1
## 4      1     12 B4 132.6752      1
## 5      1     12 B5 196.5415      1
## 6      1     12 B6 170.7482      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.1 These functions allow the aggregation to be done with a map-reduce.

The first step to making a Paasche index is to unstack the elemental indexes into a list of elemental indexes for each period. (Trying to make the elemental 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 elemental 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,
  r = -1
) |>
  Reduce(stack, x = _)

paasche
## Period-over-period price index for 3 levels over 4 time periods 
##    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 Fisher index

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 
##    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  1 1.0509134 0.9783795 0.9600792
## 11 1 1.1157686 1.0007074 0.9557479
## 12 1 0.9891911 0.9567760 0.9665552

  1. split() can also be used for this.↩︎

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.