Skip to contents

Calculate additive percent-change contributions for generalized-mean price indexes, and indexes that nest two levels of generalized means consisting of an outer generalized mean and two inner generalized means (e.g., the Fisher index).

Usage

contributions(r)

arithmetic_contributions(x, w = NULL)

geometric_contributions(x, w = NULL)

harmonic_contributions(x, w = NULL)

nested_contributions(r1, r2, t = c(1, 1))

nested_contributions2(r1, r2, t = c(1, 1))

fisher_contributions(x, w1 = NULL, w2 = NULL)

fisher_contributions2(x, w1 = NULL, w2 = NULL)

Arguments

r

A finite number giving the order of the generalized mean.

x

A strictly positive numeric vector.

w, w1, w2

A strictly positive numeric vector of weights, the same length as x. The default is to equally weight each element of x.

r1

A finite number giving the order of the outer generalized mean.

r2

A pair of finite numbers giving the order of the inner generalized means.

t

A pair of strictly positive weights for the inner generalized means. The default is equal weights.

Value

contributions() returns a function:

function(x, w = NULL){...}

This computes the additive contribution for each element of x in an index based on the generalized mean of order r with weights w.

nested_contributions() and nested_contributions2() return a function:

function(x, w1 = NULL, w2 = NULL){...}

This computes the additive contribution for each element of x when a generalized mean of order r1 aggregates a generalized-mean index of order r2[1] with weights w1 and a generalized-mean index of order r2[2] with weights w2.

arithmetic_contributions(), geometric_contributions(), and harmonic_contributions() each return a numeric vector, the same length as x, giving the contribution of each element of x in an arithmetic, geometric, or harmonic index.

fisher_contributions() and fisher_contributions2() each return a numeric vector, the same length as x, giving the contribution of each element of x when a geometric mean aggregates an arithmetic mean of x with weights w1 and a harmonic mean of x with weights w2.

Details

The function contributions() is a simple wrapper for transmute_weights(r, 1)() to calculate (additive) percent-change contributions for a price index based on a generalized mean of order r. It returns a function to compute a vector v(x, w) such that

generalized_mean(r)(x, w) - 1 == sum(v(x, w))

This generalizes the approach for calculating percent-change contributions in section 4.2 of Balk (2008) using the method by Martin (2021). The arithmetic_contributions(), geometric_contributions() and harmonic_contributions() functions cover the most important cases (i.e., r = 1, r = 0, and r = -1).

The nested_contributions() and nested_contributions2() functions are the analog of contributions() for an index based on a nested generalized mean with two levels, like a Fisher index. They return a function that calculates the contribution of each element of x when a generalized mean of order r1 aggregates two generalized-mean indexes of x with orders r2, and weights w1 and w2.

Unlike the case of a generalized-mean index, there are several ways to make contributions for an index based on nested generalized means. nested_contributions() uses a generalization of the algorithm in section 6 of Reinsdorf et al. (2002) by Martin (2021). nested_contributions2() generalizes the van IJzeren decomposition for the Fisher index (Balk, 2008, section 4.2.2) by constructing a weighted average of the contributions for both of the inner means with the approach by Martin (2021). In most cases the results are broadly similar.

The fisher_contributions() and fisher_contributions2() functions correspond to nested_contributions(0, c(1, -1))() and nested_contributions2(0, c(1, -1))(), and are appropriate for calculating percent-change contributions for a Fisher index.

References

Balk, B. M. (2008). Price and Quantity Index Numbers. Cambridge University Press.

Hallerbach, W. G. (2005). An alternative decomposition of the Fisher index. Economics Letters, 86(2):147–152

Martin, S. (2021). A note on general decompositions for price indexes. Prices Analytical Series, Statistics Canada catalogue no. 62F0014M. Statistics Canada, Ottawa.

Reinsdorf, M. B., Diewert, W. E., and Ehemann, C. (2002). Additive decompositions for Fisher, Törnqvist and geometric mean indexes. Journal of Economic and Social Measurement, 28(1-2):51–61.

Webster, M. and Tarnow-Mordi, R. C. (2019). Decomposing multilateral price indexes into the contributions of individual commodities. Journal of Official Statistics, 35(2):461–486.

See also

transmute_weights() for the underlying implementation.

Examples

x <- 2:3

#---- Contributions for a geometric index ----

geometric_mean(x) - 1 # percent change in the Jevons index
#> [1] 1.44949

geometric_contributions(x)
#> [1] 0.5505103 0.8989795

all.equal(geometric_mean(x) - 1, sum(geometric_contributions(x)))
#> [1] TRUE

# This works by first transmuting the weights in the geometric mean
# into weights for an arithmetic mean, then finding the contributions
# to the percent change

transmute_weights(0, 1)(x) * (x - 1)
#> [1] 0.5505103 0.8989795

# Not the only way to calculate contributions

transmute2 <- function(x) {
  m <- geometric_mean(x)
  (m - 1) / log(m) * log(x) / (x - 1) / length(x)
}

transmute2(x) * (x - 1) # not proportional to the method above
#> [1] 0.5607392 0.8887506
all.equal(sum(transmute2(x) * (x - 1)), geometric_mean(x) - 1)
#> [1] TRUE

# But these "transmuted" weights don't recover the geometric mean!
# Not a particularly good way to calculate contributions

isTRUE(all.equal(
  arithmetic_mean(x, transmute2(x)),
  geometric_mean(x)
))
#> [1] FALSE

# There are infinitely many ways to calculate contributions, but the
# weights from transmute_weights(0, 1)() are the *unique* weights that
# recover the geometric mean

perturb <- function(w, e) {
  w + c(e, -e) / (x - 1)
}

perturb(transmute2(x), 0.1) * (x - 1)
#> [1] 0.6607392 0.7887506
all.equal(
  sum(perturb(transmute2(x), 0.1) * (x - 1)),
  geometric_mean(x) - 1
)
#> [1] TRUE
isTRUE(all.equal(
  arithmetic_mean(x, perturb(transmute2(x), 0.1)),
  geometric_mean(x)
))
#> [1] FALSE

#---- Contributions for a Fisher index ----

p1 <- price6[[2]]
p0 <- price6[[1]]
q1 <- quantity6[[2]]
q0 <- quantity6[[1]]

# Percent-change contributions for the Fisher index in section 6 of
# Reinsdorf et al. (2002)

(con <- fisher_contributions(
  p1 / p0,
  index_weights("Laspeyres")(p0, q0),
  index_weights("Paasche")(p1, q1)
))
#> [1]  0.01782904  0.18814917  0.05792820 -0.03414299  0.18217457 -0.01088796

all.equal(sum(con), fisher_index(p1, p0, q1, q0) - 1)
#> [1] TRUE

# Not the only way

(con2 <- fisher_contributions2(
  p1 / p0,
  index_weights("Laspeyres")(p0, q0),
  index_weights("Paasche")(p1, q1)
))
#> [1]  0.01782865  0.18815627  0.05792735 -0.03414531  0.18217135 -0.01088828

all.equal(sum(con2), fisher_index(p1, p0, q1, q0) - 1)
#> [1] TRUE

# The same as the van IJzeren decomposition in section 4.2.2 of
# Balk (2008)

Qf <- quantity_index(fisher_index)(q1, q0, p1, p0)
Ql <- quantity_index(laspeyres_index)(q1, q0, p0)
wl <- scale_weights(index_weights("Laspeyres")(p0, q0))
wp <- scale_weights(index_weights("HybridPaasche")(p0, q1))

(Qf / (Qf + Ql) * wl + Ql / (Qf + Ql) * wp) * (p1 / p0 - 1)
#> [1]  0.01782865  0.18815627  0.05792735 -0.03414531  0.18217135 -0.01088828

# Similar to the method in section 2 of Reinsdorf et al. (2002),
# although those contributions aren't based on weights that sum to 1

Pf <- fisher_index(p1, p0, q1, q0)
Pl <- laspeyres_index(p1, p0, q0)

(1 / (1 + Pf) * wl + Pl / (1 + Pf) * wp) * (p1 / p0 - 1)
#> [1]  0.01760668  0.18766299  0.05803833 -0.03510719  0.18397180 -0.01112258

# Also similar to the decomposition by Hallerbach (2005), noting that
# the Euler weights are close to unity

Pp <- paasche_index(p1, p0, q1)

(0.5 * sqrt(Pp / Pl) * wl + 0.5 * sqrt(Pl / Pp) * wp) * (p1 / p0 - 1)
#> [1]  0.01781577  0.18809422  0.05791874 -0.03417605  0.18220228 -0.01089519

#---- Contributions for other types of indexes ----

# A function to get contributions for any superlative quadratic mean of
# order 'r' index

superlative_contributions <- function(r) {
  nested_contributions(0, c(r / 2, -r / 2))
}

# Can be used to decompose the implict Walsh index

superlative_contributions(1)(
  p1 / p0,
  index_weights("Laspeyres")(p0, q0),
  index_weights("Paasche")(p1, q1)
)
#> [1]  0.01797225  0.18686566  0.05817035 -0.03351992  0.18283997 -0.01079435

# Works for other types of indexes, like the harmonic
# Laspeyres Paasche index

hlp_contributions <- nested_contributions(-1, c(1, -1))
hlp_contributions(
  p1 / p0,
  index_weights("Laspeyres")(p0, q0),
  index_weights("Paasche")(p1, q1)
)
#> [1]  0.01781416  0.18807725  0.05791352 -0.03417296  0.18218584 -0.01089421

# Or the AG mean index (tau = 0.25)

agmean_contributions <- nested_contributions(1, c(0, 1), c(0.25, 0.75))
agmean_contributions(
  p1 / p0,
  index_weights("Laspeyres")(p0, q0),
  index_weights("Laspeyres")(p0, q0)
)
#> [1]  0.02020872  0.18206588  0.06001941 -0.03256065  0.17841536 -0.01065698

# Or the Balk-Walsh index

bw_contributions <- nested_contributions(0, c(0.5, -0.5))
bw_contributions(p1 / p0)
#> [1]  0.03304293  0.20895332  0.04762026 -0.06488592  0.06118424 -0.04046550