diff --git a/DESCRIPTION b/DESCRIPTION index 3b4e63b1..a244bf72 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: piar Title: Price Index Aggregation -Version: 0.9.0.9006 +Version: 0.9.0.9007 Authors@R: c( person("Steve", "Martin", role = c("aut", "cre", "cph"), email = "marberts@protonmail.com", @@ -23,10 +23,11 @@ Imports: stats, utils, Matrix (>= 1.5-0) -Suggests: +Suggests: data.tree, - knitr, - quarto, + litedown, + rsmatrix, + spelling, sps, tinytest, treemap @@ -35,6 +36,7 @@ Encoding: UTF-8 URL: https://marberts.github.io/piar/, https://github.com/marberts/piar BugReports: https://github.com/marberts/piar/issues LazyData: true -VignetteBuilder: quarto +VignetteBuilder: litedown Roxygen: list(markdown = TRUE) Config/roxygen2/version: 8.0.0 +Language: en-US diff --git a/NAMESPACE b/NAMESPACE index 4057f9a6..774588b9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -89,8 +89,6 @@ export(aggregation_structure) export(as_aggregation_structure) export(as_index) export(back_period) -export(carry_backward) -export(carry_forward) export(chain) export(combine_classifications) export(contrib) @@ -119,7 +117,6 @@ export(set_contrib_from_index) export(set_levels) export(set_time) export(set_weights) -export(shadow_price) export(splice_index) export(split_classification) export(transmute_weights) diff --git a/NEWS.md b/NEWS.md index 0fcd845c..d3946ecd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,7 +12,7 @@ two separate packages. In particular: - Core mathematical machinery used to aggregate indexes and make product contributions. - - A new vignette outlining some theory that unlies how indexes are calculated. + - A new vignette outlining some theory that underlies how indexes are calculated. - The argument `r` in `elementary_index()`, `aggregate()`, `mean()`, `update()`, and `impute_prices()` is deprecated and will be removed in a future version. @@ -31,6 +31,8 @@ contributions. - `impute_prices()` no longer matches missing products across consecutive time periods when passed a matrix. +- `impute_prices()` no longer returns all `NA`s with no time periods. + - Setting `include_ea = FALSE` in `aggregate(index)` no longer gives an error with a one-level aggregation structure. diff --git a/R/aggregate.piar_index.R b/R/aggregate.piar_index.R index 87ca0afa..85f93021 100644 --- a/R/aggregate.piar_index.R +++ b/R/aggregate.piar_index.R @@ -49,9 +49,9 @@ #' #' If two aggregation structures are given then the steps above are done for #' each aggregation structure, with the aggregation for `pias` done with a -#' generalized mean of order `r` the aggregation for `pias2` done with a -#' generalized mean of order `-r`. The resulting indexes are combined with a -#' geometric mean to make a superlative quadratic mean of order `2*r` index. +#' generalized mean of order `order` the aggregation for `pias2` done with a +#' generalized mean of order `-order`. The resulting indexes are combined with a +#' geometric mean to make a superlative quadratic mean of order `2*order` index. #' Percent-change contributions are combined using a generalized van IJzeren #' decomposition; see [`transmute_weights2()`] for details. #' diff --git a/R/aggregation_structure-class.R b/R/aggregation_structure-class.R index 036d1170..1decc7dd 100644 --- a/R/aggregation_structure-class.R +++ b/R/aggregation_structure-class.R @@ -22,6 +22,9 @@ piar_aggregation_structure <- function(child, parent, levels, weights) { } #---- Validator ---- +# The first two validators are not extensively used and duplicate checking +# already done by aggregation_structure(). They're here in case a validator +# is needed in the future. validate_pias_levels <- function(x) { lev <- unlist(x$levels, use.names = FALSE) if (missing_names(lev)) { diff --git a/R/aggregation_structure.R b/R/aggregation_structure.R index 507a7d23..3ea1e1a2 100644 --- a/R/aggregation_structure.R +++ b/R/aggregation_structure.R @@ -124,7 +124,7 @@ aggregation_structure <- function(x, weights = NULL) { } upper <- x[-len] # nodes above eas lower <- x[-1L] # nodes below initial nodes - child <- parent <- vector("list", len)[-1L] + child <- parent <- vector("list", length(upper)) # Produce a list for each level with all the parent and child nodes. for (i in seq_along(upper)) { child[[i]] <- lapply( diff --git a/R/back_period.R b/R/back_period.R index 0317b339..97376ed7 100644 --- a/R/back_period.R +++ b/R/back_period.R @@ -66,25 +66,28 @@ back_period <- function( x[c(rep.int(1L, offset), seq_len(length(x) - offset))] } offset <- as.integer(offset) - if (offset < 0L || offset > length(period)) { - stop("`offset` must be a positive integer less than the length of `period`") - } period <- as.factor(period) - product <- as.factor(product %||% gl(1, length(period))) - attributes(product) <- NULL # matching is faster on factor codes + if (!is.null(product)) { + product <- as.factor(product) + attributes(product) <- NULL # matching is faster on factor codes + } else { + product <- rep.int(1L, length(period)) + } if (length(period) != length(product)) { stop("`period` and `product` must be the same length") } - # Factors with no levels throw an error below. - if (nlevels(period) == 0L) { - return(rep.int(NA_integer_, length(period))) + if (offset < 0L || offset > nlevels(period)) { + stop("`offset` must be a positive integer less than `nlevels(period)`") } product <- split(product, period) if (duplicate_products(product)) { warning("there are duplicated period-product pairs") } + if (offset == 0L) { + return(seq_along(period)) + } m <- Map(match, product, f(product, offset), incomparables = NA) if (!match_first) { m[seq_len(offset)][] <- NA_integer_ diff --git a/R/combine_classifications.R b/R/combine_classifications.R index e738139e..e64d8788 100644 --- a/R/combine_classifications.R +++ b/R/combine_classifications.R @@ -29,7 +29,7 @@ combine_classifications <- function(..., sep = ".") { dots <- lapply(list(...), \(x) lapply(x, as.character)) Reduce( - \(x, y) combine_classifications_(x, y, sep = sep), + \(x, y) .combine_classifications(x, y, sep = sep), dots, simplify = FALSE ) @@ -37,7 +37,7 @@ combine_classifications <- function(..., sep = ".") { #' Combine classifications (internal) #' @noRd -combine_classifications_ <- function(x, y, sep) { +.combine_classifications <- function(x, y, sep) { lx <- lengths(x) if (length(lx) == 0L) { return(y) diff --git a/R/contrib.R b/R/contrib.R index 95169241..c9eda553 100644 --- a/R/contrib.R +++ b/R/contrib.R @@ -56,8 +56,8 @@ #' contrib2DF(index) #' #' # Calculate EA contributions for the chained index. -#' arithmetic_contributions <- function(x, w, r = 1) { -#' (x - 1) * transmute_weights(x, w, r, to = 1) +#' arithmetic_contributions <- function(x, w, order = 1) { +#' (x - 1) * transmute_weights(x, w, order, to = 1) #' } #' #' arithmetic_contributions( diff --git a/R/elementary_index.R b/R/elementary_index.R index 27fcf2d0..72241edb 100644 --- a/R/elementary_index.R +++ b/R/elementary_index.R @@ -14,7 +14,7 @@ #' be unique within each elementary aggregate at each time period when making #' contributions and, if not, are #' passed to [make.unique()] with a warning. The default -#' (\code{r = 0} and no weights) makes Jevons elementary indexes. See chapter 8 +#' (`order = 0` and no weights) makes Jevons elementary indexes. See chapter 8 #' (pp. 175--190) of the CPI manual (2020) for more detail about making #' elementary indexes, or chapter 9 of the PPI manual (2004), and chapter 5 of #' Balk (2008). @@ -161,7 +161,7 @@ #' prices, #' rel ~ period + ea, #' weights = unsplit(cswd_weights, interaction(period, ea)), -#' r = 1 +#' order = 1 #' ) elementary_index <- function(x, ...) { if ("r" %in% ...names()) { @@ -201,8 +201,11 @@ elementary_index.numeric <- function( r <- as.numeric(r) period <- as.factor(period %||% gl(1, length(x))) ea <- as.factor(ea %||% gl(1, length(x))) + if (!is.null(product)) { + product <- as.character(product) + } - if (different_length(x, period, ea, weights)) { + if (different_length(x, period, ea, weights, product)) { stop("input vectors must be the same length") } if (any(x <= 0, na.rm = TRUE)) { @@ -214,7 +217,7 @@ elementary_index.numeric <- function( if (contrib) { if (!is.null(product)) { - names(x) <- as.character(product) + names(x) <- product } if (is.null(names(x))) { names(x) <- paste(ea, sequential_names(period, ea), sep = ".") diff --git a/R/emean.R b/R/emean.R index 49233562..cbccb597 100644 --- a/R/emean.R +++ b/R/emean.R @@ -78,12 +78,12 @@ emean <- function( # length of the other. if (length(x) > length(y)) { if (length(y) > 0 && length(x) %% length(y) != 0) { - warning("length of `y` is not a multiple of length of `x`") + warning("length of `x` is not a multiple of length of `y`") y <- rep_len(y, length(x)) } } else if (length(x) < length(y)) { if (length(x) > 0 && length(y) %% length(x) != 0) { - warning("length of `x` is not a multiple of length of `y`") + warning("length of `y` is not a multiple of length of `x`") x <- rep_len(x, length(y)) } } @@ -104,7 +104,7 @@ emean <- function( } else { res <- ((x^s - y^s) / (x^r - y^r) * (r / s))^(1 / (s - r)) } - # Set output to a when a == b. + # Set output to `x` when `x` == `y`. i <- which(abs(x - y) <= tol) res[i] <- x[(i - 1L) %% length(x) + 1L] res diff --git a/R/geks_index.R b/R/geks_index.R index 56208667..99e8673b 100644 --- a/R/geks_index.R +++ b/R/geks_index.R @@ -53,10 +53,12 @@ #' subtle implications for a multilateral index. #' #' @seealso +#' [`splice_index()`] to splice the rolling-window indexes together. +#' #' `GEKSIndex()` in the \pkg{IndexNumR} package for an implementation of the #' GEKS index with more options. #' -#' [`splice_index()`] to splice the rolling-window indexes together. +#' The \pkg{rsmatrix} package for multilateral repeat-sales indexes. #' #' @references #' Balk, B. M. (2008). *Price and Quantity Index Numbers*. @@ -125,8 +127,8 @@ geks_index <- function( } window <- as.integer(window) - if (length(window) > 1L || window < 2L) { - stop("`window` must be a integer greater than or equal to 2") + if (window < 2L) { + stop("`window` must be greater than or equal to 2") } if (window > nlevels(period)) { stop( @@ -136,8 +138,8 @@ geks_index <- function( } n <- as.integer(n) - if (length(n) > 1L || n < 1L) { - stop("`n` must be an integer greater than or equal to 1") + if (n < 1L) { + stop("`n` must be greater than or equal to 1") } if (n > window - 1L) { stop("`n` must be less than or equal to `window` minus 1") diff --git a/R/gmean.R b/R/gmean.R index 1a67f28b..bcbeb242 100644 --- a/R/gmean.R +++ b/R/gmean.R @@ -5,7 +5,7 @@ #' The generalized mean is also called the power mean, Hölder mean, or \eqn{l_p} #' mean; see Bullen (2003, p. 175) for details. #' -#' Both `x` and `weights` should be strictly positive +#' Both `x` and `weights` are usually strictly positive #' (and finite), especially for the purpose of making a price index. This is not #' enforced, but the results may not make sense if the generalized mean is not #' defined. There are two exceptions to this. @@ -15,7 +15,7 @@ #' one element of `x` is `Inf`: the generalized mean is `Inf` whenever the #' weights are strictly positive and `order > 0`. #' -#' 2. Some authors let the weighs be non-negative and sum to 1. If there are +#' 2. Some authors let the weights be non-negative and sum to 1. If there are #' zero weights then the corresponding element #' of `x` has no impact on the result whenever `x` is strictly #' positive. Unlike [weighted.mean()], however, diff --git a/R/impute_prices.R b/R/impute_prices.R index 0de56e0c..0c72c81e 100644 --- a/R/impute_prices.R +++ b/R/impute_prices.R @@ -154,12 +154,15 @@ impute_prices.matrix <- function( # it just does it period-by-period and keeps track of prices to impute. chkDots(...) method <- match.arg(method) - period <- as.factor(period) - product <- as.factor(product) - attributes(product) <- NULL if (not_finite_pair(r)) { stop("`r` must be a pair of finite numbers") } + if (ncol(x) != 2L) { + stop("`x` must be a two-column matrix") + } + period <- as.factor(period) + product <- as.factor(product) + attributes(product) <- NULL if (!is.null(ea)) { ea <- as.factor(ea) } @@ -170,9 +173,6 @@ impute_prices.matrix <- function( if (different_length(x[, 1L], period, product, ea, weights)) { stop("input vectors must be the same length") } - if (nlevels(period) == 0L) { - return(matrix(NA_real_, nrow = length(period), ncol = 2)) - } res <- split.data.frame(x, period) product <- split(product, period) @@ -253,15 +253,15 @@ impute_prices.numeric <- function( # it just does it period-by-period and keeps track of prices to impute. chkDots(...) method <- match.arg(method) + if (not_finite_pair(r)) { + stop("`r` must be a pair of finite numbers") + } period <- as.factor(period) if (method == "carry-backward") { period <- factor(period, rev(levels(period))) } product <- as.factor(product) attributes(product) <- NULL - if (not_finite_pair(r)) { - stop("`r` must be a pair of finite numbers") - } if (!is.null(ea)) { ea <- as.factor(ea) } @@ -272,9 +272,6 @@ impute_prices.numeric <- function( if (different_length(x, period, product, ea, weights)) { stop("input vectors must be the same length") } - if (nlevels(period) == 0L) { - return(rep.int(NA_real_, length(period))) - } res <- split(x, period) product <- split(product, period) @@ -329,7 +326,8 @@ impute_prices.numeric <- function( res[[t]][impute] <- res[[t - 1L]][matches] } } - unsplit(res, period) + split(x, period) <- res + x } #' @rdname impute_prices @@ -354,24 +352,3 @@ impute_prices.data.frame <- function( ... ) } - -#' @rdname impute_prices -#' @export -carry_forward <- function(x, ...) { - warning("'carry_forward() is deprecated; use 'impute_prices()' instead") - impute_prices(x, method = "carry-forward", ...) -} - -#' @rdname impute_prices -#' @export -carry_backward <- function(x, ...) { - warning("'carry_backward() is deprecated; use 'impute_prices()' instead") - impute_prices(x, method = "carry-backward", ...) -} - -#' @rdname impute_prices -#' @export -shadow_price <- function(x, ...) { - warning("'shadow_price() is deprecated; use 'impute_prices()' instead") - impute_prices(x, method = "overall-mean", ...) -} diff --git a/R/window.piar_index.R b/R/window.piar_index.R index bbb18f28..514f783a 100644 --- a/R/window.piar_index.R +++ b/R/window.piar_index.R @@ -9,7 +9,8 @@ #' @param end `[character(1)]` The time period to end the window. The default #' is the last period of `x`. #' @param ... Not currently used. -#' @param value `[numeric > 0 | piar_index]` A numeric vector or price index. +#' @param value `[numeric > 0 | piar_index]` A numeric vector or price index +#' of replacement values. #' #' @returns #' `window()` extracts a price index over a window of time periods that diff --git a/inst/WORDLIST b/inst/WORDLIST new file mode 100644 index 00000000..9c44b953 --- /dev/null +++ b/inst/WORDLIST @@ -0,0 +1,85 @@ +Berthelot +Bigg +Bullen +CBO +CMD +COICOP +Carli +Carruthers +Chessa +Coggeshall +Conda +Dalén +Deprecations +Diewert +Eurostat +FEWS +GEKS +Github +Hidiroglou +Hölder +IJzeren +ILO +Ivancic +Janeiro +Jevons +Kimber +Krsinich +Laspeyres +Lehmer +Lippe +Littlewood +NAICS +NAPCS +ORCID +PPI +Paasche +Polya +RStudio +Rais +Rebase +Rebasing +Sellwood +Springer +Stolarsky +Subscripting +Törnqvist +UNECE +Vartia +al +antiharmonic +chainable +codecov +de +deflators +der +doi +eq +equalities +et +frac +geq +gpindex +ldots +leq +lexicographically +mathbb +mathbf +mathfrak +nd +neq +parentally +pias +pre +reaggregate +reaggregating +rebase +rebased +rebasing +subperiods +subscripting +th +unstack +varepsilon +varsigma +von diff --git a/inst/tinytest/test-back_period.R b/inst/tinytest/test-back_period.R index cc91179a..441ac7c8 100644 --- a/inst/tinytest/test-back_period.R +++ b/inst/tinytest/test-back_period.R @@ -50,8 +50,8 @@ local({ c(1L, 2L, 3L, 4L, 4L, 3L, 2L, 1L, NA) ) expect_identical( - back_period(factor(period, levels = NA), id), - rep(NA_integer_, 10) + back_period(factor(period, levels = NA), id, offset = 0), + 1:10 ) # Change time periods again @@ -83,6 +83,16 @@ local({ # Warnings and errors. local({ - expect_warning(back_period(c(1, 1, 2, 3))) - expect_error(back_period(1:5, 1:4)) + expect_warning( + back_period(c(1, 1, 2, 3)), + "there are duplicated period-product pairs" + ) + expect_error( + back_period(1:5, 1:4), + "`period` and `product` must be the same length" + ) + expect_error( + back_period(c(1, 1, 2, 2), c(1, 2, 1, 2), offset = 3), + "`offset` must be a positive integer less than `nlevels\\(period\\)`" + ) }) diff --git a/inst/tinytest/test-emean.R b/inst/tinytest/test-emean.R index 612b0ead..f72f6039 100644 --- a/inst/tinytest/test-emean.R +++ b/inst/tinytest/test-emean.R @@ -76,7 +76,7 @@ expect_error( # Recycling works expect_warning( emean(1:3, 1:5), - "length of `x` is not a multiple of length of `y`" + "length of `y` is not a multiple of length of `x`" ) expect_equal( suppressWarnings(emean(1:3, 1:5)), @@ -86,7 +86,7 @@ expect_equal(emean(1:5, numeric(0)), numeric(0)) expect_warning( emean(1:5, 1:3), - "length of `y` is not a multiple of length of `x`" + "length of `x` is not a multiple of length of `y`" ) expect_equal( suppressWarnings(emean(1:5, 1:3)), diff --git a/inst/tinytest/test-impute-prices.R b/inst/tinytest/test-impute-prices.R index 84ca4a2a..5a46f153 100644 --- a/inst/tinytest/test-impute-prices.R +++ b/inst/tinytest/test-impute-prices.R @@ -45,7 +45,7 @@ local({ pias = pias, method = "overall-mean" ), - matrix(numeric(0), 0, 2) + cbind(integer(0), integer(0)) ) }) @@ -179,7 +179,7 @@ local({ ) }) -# Carrying forward/backwards imputation works.s +# Carrying forward/backwards imputation works. local({ df <- data.frame( price = c(NA, 1, 2, NA, 3), @@ -219,6 +219,11 @@ local({ ), matrix(c(1, 2, 1, 4, 5, 6, 3, 2, 1, 1, 2, 3), ncol = 2) ) + + expect_error( + impute_prices(matrix(1:9, 3), period = 1:3, product = 1:3), + "`x` must be a two-column matrix" + ) }) # NA products don't get imputed. diff --git a/man/aggregate.piar_index.Rd b/man/aggregate.piar_index.Rd index f8220236..d4cc5b81 100644 --- a/man/aggregate.piar_index.Rd +++ b/man/aggregate.piar_index.Rd @@ -136,9 +136,9 @@ contributions will not equal the change in the value of the index. If two aggregation structures are given then the steps above are done for each aggregation structure, with the aggregation for \code{pias} done with a -generalized mean of order \code{r} the aggregation for \code{pias2} done with a -generalized mean of order \code{-r}. The resulting indexes are combined with a -geometric mean to make a superlative quadratic mean of order \code{2*r} index. +generalized mean of order \code{order} the aggregation for \code{pias2} done with a +generalized mean of order \code{-order}. The resulting indexes are combined with a +geometric mean to make a superlative quadratic mean of order \code{2*order} index. Percent-change contributions are combined using a generalized van IJzeren decomposition; see \code{\link[=transmute_weights2]{transmute_weights2()}} for details. } diff --git a/man/contrib.Rd b/man/contrib.Rd index b5b45f6b..aa2814c9 100644 --- a/man/contrib.Rd +++ b/man/contrib.Rd @@ -77,8 +77,8 @@ contrib(index) contrib2DF(index) # Calculate EA contributions for the chained index. -arithmetic_contributions <- function(x, w, r = 1) { - (x - 1) * transmute_weights(x, w, r, to = 1) +arithmetic_contributions <- function(x, w, order = 1) { + (x - 1) * transmute_weights(x, w, order, to = 1) } arithmetic_contributions( diff --git a/man/elementary_index.Rd b/man/elementary_index.Rd index 84e335fc..ae6a92c2 100644 --- a/man/elementary_index.Rd +++ b/man/elementary_index.Rd @@ -108,7 +108,7 @@ should be unique within each elementary aggregate at each time period when making contributions and, if not, are passed to \code{\link[=make.unique]{make.unique()}} with a warning. The default -(\code{r = 0} and no weights) makes Jevons elementary indexes. See chapter 8 +(\code{order = 0} and no weights) makes Jevons elementary indexes. See chapter 8 (pp. 175--190) of the CPI manual (2020) for more detail about making elementary indexes, or chapter 9 of the PPI manual (2004), and chapter 5 of Balk (2008). @@ -171,7 +171,7 @@ elementary_index( prices, rel ~ period + ea, weights = unsplit(cswd_weights, interaction(period, ea)), - r = 1 + order = 1 ) } \references{ diff --git a/man/geks_index.Rd b/man/geks_index.Rd index c71bb3a8..7247f0cb 100644 --- a/man/geks_index.Rd +++ b/man/geks_index.Rd @@ -118,8 +118,10 @@ aggregation and the construction of price indexes. \emph{Journal of Econometrics}, 161(1): 24--35. } \seealso{ +\code{\link[=splice_index]{splice_index()}} to splice the rolling-window indexes together. + \code{GEKSIndex()} in the \pkg{IndexNumR} package for an implementation of the GEKS index with more options. -\code{\link[=splice_index]{splice_index()}} to splice the rolling-window indexes together. +The \pkg{rsmatrix} package for multilateral repeat-sales indexes. } diff --git a/man/gmean.Rd b/man/gmean.Rd index 434c3a11..cfc6de2f 100644 --- a/man/gmean.Rd +++ b/man/gmean.Rd @@ -28,7 +28,7 @@ Calculated a weighted generalized mean. The generalized mean is also called the power mean, Hölder mean, or \eqn{l_p} mean; see Bullen (2003, p. 175) for details. -Both \code{x} and \code{weights} should be strictly positive +Both \code{x} and \code{weights} are usually strictly positive (and finite), especially for the purpose of making a price index. This is not enforced, but the results may not make sense if the generalized mean is not defined. There are two exceptions to this. @@ -38,7 +38,7 @@ has zeros: the generalized mean is 0 whenever the weights are strictly positive and \code{order < 0}. The analogous convention holds whenever at least one element of \code{x} is \code{Inf}: the generalized mean is \code{Inf} whenever the weights are strictly positive and \code{order > 0}. -\item Some authors let the weighs be non-negative and sum to 1. If there are +\item Some authors let the weights be non-negative and sum to 1. If there are zero weights then the corresponding element of \code{x} has no impact on the result whenever \code{x} is strictly positive. Unlike \code{\link[=weighted.mean]{weighted.mean()}}, however, diff --git a/man/impute_prices.Rd b/man/impute_prices.Rd index f6b82e59..448867c9 100644 --- a/man/impute_prices.Rd +++ b/man/impute_prices.Rd @@ -6,9 +6,6 @@ \alias{impute_prices.matrix} \alias{impute_prices.numeric} \alias{impute_prices.data.frame} -\alias{carry_forward} -\alias{carry_backward} -\alias{shadow_price} \title{Impute missing prices} \usage{ impute_prices(x, ...) @@ -44,12 +41,6 @@ impute_prices(x, ...) ) \method{impute_prices}{data.frame}(x, formula, ..., ea = NULL, weights = NULL) - -carry_forward(x, ...) - -carry_backward(x, ...) - -shadow_price(x, ...) } \arguments{ \item{x}{\verb{[object]} Either a numeric vector (or something that can be diff --git a/man/window.piar_index.Rd b/man/window.piar_index.Rd index e2219bec..2127cf24 100644 --- a/man/window.piar_index.Rd +++ b/man/window.piar_index.Rd @@ -21,7 +21,8 @@ is the last period of \code{x}.} \item{...}{Not currently used.} -\item{value}{\verb{[numeric > 0 | piar_index]} A numeric vector or price index.} +\item{value}{\verb{[numeric > 0 | piar_index]} A numeric vector or price index +of replacement values.} } \value{ \code{window()} extracts a price index over a window of time periods that diff --git a/tests/spelling.R b/tests/spelling.R new file mode 100644 index 00000000..d60e024c --- /dev/null +++ b/tests/spelling.R @@ -0,0 +1,7 @@ +if (requireNamespace("spelling", quietly = TRUE)) { + spelling::spell_check_test( + vignettes = TRUE, + error = FALSE, + skip_on_cran = TRUE + ) +} diff --git a/tests/test-making-price-indexes.R b/tests/test-making-price-indexes.R index e47a2865..08efed74 100644 --- a/tests/test-making-price-indexes.R +++ b/tests/test-making-price-indexes.R @@ -1,9 +1,3 @@ -## ----include = FALSE---------------------------------------------------------- -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) - ## ----------------------------------------------------------------------------- library(piar) diff --git a/tests/test-making-price-indexes.Rout.save b/tests/test-making-price-indexes.Rout.save index b487c1f1..f4f5e09e 100644 --- a/tests/test-making-price-indexes.Rout.save +++ b/tests/test-making-price-indexes.Rout.save @@ -15,12 +15,6 @@ Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. -> ## ----include = FALSE---------------------------------------------------------- -> knitr::opts_chunk$set( -+ collapse = TRUE, -+ comment = "#>" -+ ) -> > ## ----------------------------------------------------------------------------- > library(piar) > diff --git a/vignettes/adjust-weights.qmd b/vignettes/adjust-weights.Rmd similarity index 96% rename from vignettes/adjust-weights.qmd rename to vignettes/adjust-weights.Rmd index 1a591fce..e23c9186 100644 --- a/vignettes/adjust-weights.qmd +++ b/vignettes/adjust-weights.Rmd @@ -2,12 +2,8 @@ title: "Adjusting annual weights" vignette: > %\VignetteIndexEntry{Adjusting annual weights} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- Making a monthly or quarterly Lowe index with annual expenditure or revenue diff --git a/vignettes/contributions.qmd b/vignettes/contributions.Rmd similarity index 96% rename from vignettes/contributions.qmd rename to vignettes/contributions.Rmd index d4de1abe..f4746f4b 100644 --- a/vignettes/contributions.qmd +++ b/vignettes/contributions.Rmd @@ -2,12 +2,8 @@ title: "Contributions" vignette: > %\VignetteIndexEntry{Contributions} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- ## Product contributions diff --git a/vignettes/decomposing-indexes.Rmd b/vignettes/decomposing-indexes.Rmd new file mode 100644 index 00000000..4a7281fc --- /dev/null +++ b/vignettes/decomposing-indexes.Rmd @@ -0,0 +1,317 @@ +--- +title: "Decomposing price indexes" +format: + html: + html-math-method: mathjax + options: + number_sections: true +vignette: > + %\VignetteIndexEntry{Decomposing price indexes} + %\VignetteEngine{litedown::vignette} + %\VignetteEncoding{UTF-8} +--- + +*This vignette presents an extended version of Martin (2021), and shows how to use the tools in this package to make these decompositions.* + +It is often useful to be able to decompose a price index into an additive or multiplicative form to evaluate how each input to the index affects its value. Following Balk (2008), a price index is said to admit an additive decomposition if there exist weights that allow it to be represented as an arithmetic mean of price relatives, and is said to admit a multiplicative decomposition if there are weights that allow it to be represented as a geometric mean. Switching prices for quantities gives the analogous statements for a quantity index, and nothing is lost by focusing on price indexes. + +There are several well-known decompositions for the most common types of bilateral price indexes. Balk (2008, eq. 4.13) gives an additive decomposition for any index based on the geometric mean by transmuting the weights in the geometric mean with the logarithmic mean. This is the same decomposition derived by Reinsdorf et al. (2002, eq. 20) for the Törnqvist index. A similar approach yields a multiplicative decomposition for any index based on the arithmetic mean, again using the logarithmic mean (Balk, 2008, eq. 4.8). Combining these results gives additive and multiplicative decompositions for the Fisher index (Reinsdorf et al., 2002, sec. 6). The van IJzeren additive decomposition for the Fisher index (Balk, 2008, eq. 4.18) is an alternative that does not explicitly use the logarithmic mean. Each of these decompositions results in weights that are positive and sum to one, as required to represent an index as an arithmetic or geometric mean.[^1] + +[^1]: There are decompositions with "weights" that do not sum to one, such as those for the Fisher index by Reinsdorf et al. (2002, sec. 2) and Hallerbach (2005), and for other superlative indexes by Diewert (2002). Balk (2008, eq. 4.28) gives the original multiplicative decomposition of the Fisher index, due to Vartia, for which the weights also do not sum to one. Webster and Tarnow-Mordi (2019) consider several decompositions for multilateral indexes, although again the "weights" do not sum to one. + +I show how the additive and multiplicative decompositions for geometric, arithmetic, and Fisher indexes can be consolidated and made more general by switching out the logarithmic mean for the more general extended mean. The main result is a function that transmutes the weights in a generalized mean of a given order so that it can be represented as a generalized mean of any other order. This covers additive and multiplicative decompositions for indexes that do not belong to the arithmetic or geometric families, like harmonic indexes or the Lloyd-Moulton index, and allows both additive and multiplicative decompositions to be covered by a single equation, rather than treating them as different cases. Expressing a generalized-mean index as a generalized mean of any other order also allows for the decomposition of indexes that are nested generalized means, like the family of superlative quadratic mean indexes that includes the Fisher index or the AG mean index by Lent and Dorfman (2009). I demonstrate some useful properties of this general decomposition and show how it can be used to decompose indexes based on other types on means, including those that aggregate indexes according to a hierarchical structure, and decompose deflating a change in aggregate values with a price index. See Martin (2026) for an application of these methods to multilateral indexes. Throughout I show how the tools in the **piar** package can be used to decompose a price index. + +## Decomposing generalized-mean indexes {#sec-decompose} + +A natural extension to the decompositions of indexes based on the arithmetic and geometric means is to derive weights that transform an index based on a generalized mean of order $\rho$ into one based on a generalized mean of order $\varsigma$. To fix notation, let $\mathbf{r} = (r_{1}, r_{2}, \ldots, r_{n}) \in \mathbb{R}^{n}_{++}$ be a vector of price relatives for $n\geq2$ products and let $\mathbf{w} = (w_{1}, w_{2}, \ldots, w_{n}) \in \Delta^{n - 1}$ be the corresponding weights, where $\Delta^{n - 1} = \{\mathbf{w} \in \mathbb{R}_{+}^{n} | \sum_{i = 1}^{n} w_{i} = 1\}$ is the unit simplex. The goal is to find a vector-valued function +$$\mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) = (v_{1}(\mathbf{r}, \mathbf{w}; \rho, \varsigma), v_{2}(\mathbf{r}, \mathbf{w}; \rho, \varsigma),\ldots, v_{n}(\mathbf{r}, \mathbf{w}; \rho, \varsigma))$$ +mapping into $\Delta^{n - 1}$ such that +$$\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) \equiv \mathfrak{M}_{\varsigma}(\mathbf{r}, \mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \varsigma)),$$ +where $\mathfrak{M}_{\rho}$ is the generalized mean +$$\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) = +\begin{cases} +\left(\sum_{i = 1}^{n} w_{i} r_i^{\rho}\right)^{1 / \rho} & \text{if } \rho \neq 0 \\ +\prod_{i = 1}^{n} r_{i}^{w_{i}} & \text{if } \rho = 0. +\end{cases}$$ + +Setting $\varsigma = 1$ then yields an additive decomposition for any index based on a generalized mean of order $\rho$, such that +$$\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) = \sum_{i=1}^{n} r_{i} v_i(\mathbf{r}, \mathbf{w}; \rho, 1),$$ +and setting $\varsigma = 0$ yields a multiplicative decomposition, such that +$$\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) = \prod_{i=1}^{n} r_{i}^{ v_i(\mathbf{r}, \mathbf{w}; \rho, 0)}.$$ +Note that any index that admits an additive decomposition can be used to derive percent-change contributions for each price relative, $v_i(\mathbf{r}, \mathbf{w}; \rho, 1) (r_i - 1)$, that sum up to $\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) - 1$, although the converse is not true and it is possible to decompose an index into percent-change contributions that do not allow it to be represented as an arithmetic mean. Note also that other types of decompositions can be had by setting $\varsigma$ to a value other than 0 or 1; for example, setting $\varsigma = -1$ gives the harmonic decomposition (Färe and Karagiannis, 2025), +$$\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) = 1 / \left(\sum_{i=1}^{n} v_i(\mathbf{r}, \mathbf{w}; \rho, -1) / r_{i}\right),$$ +that will be useful in @sec:harmonic. + +Balk (2008) and Reinsdorf et al. (2002) show how to derive $\mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \varsigma)$ when $\rho = 1$ and $\varsigma = 0$ (multiplicative decomposition of an arithmetic index) +$$v_{i}(\mathbf{r}, \mathbf{w}; 1, 0) = \frac{w_{i} \mathfrak{L}(r_{i}, \mathfrak{M}_{1}(\mathbf{r}, \mathbf{w}))}{\sum_{j=1}^{n} w_{j} \mathfrak{L}(r_{j}, \mathfrak{M}_{1}(\mathbf{r}, \mathbf{w}))}$$ +and $\rho = 0$ and $\varsigma = 1$ (additive decomposition of a geometric index) +$$v_{i}(\mathbf{r}, \mathbf{w}; 0, 1) = \frac{w_{i} / \mathfrak{L}(r_{i}, \mathfrak{M}_{0}(\mathbf{r}, \mathbf{w}))}{\sum_{j=1}^{n} w_{j} / \mathfrak{L}(r_{j}, \mathfrak{M}_{0}(\mathbf{r}, \mathbf{w}))},$$ +using the logarithmic mean +$$\mathfrak{L}(a, b) = +\begin{cases} +\frac{a - b}{\log(a / b)} & a \neq b\\ +a & a = b. +\end{cases}$$ + +Generalizing these results follows from replacing the logarithmic mean with the more general extended mean (Bullen, 2003, p. 393), defined for any $a,b > 0$ as +$$\mathfrak{E}_{\rho\varsigma}(a, b) = +\begin{cases} +\left(\frac{\varsigma(a^\rho - b^\rho)}{\rho(a^\varsigma - b^\varsigma)}\right)^{1 / (\rho - \varsigma)} & \rho \neq \varsigma, \rho \neq 0, \varsigma \neq 0, a \neq b \\ +\left(\frac{a^\rho - b^\rho}{\rho\log(a / b)}\right)^{1 / \rho} & \rho \neq 0, \varsigma = 0, a \neq b \\ +\left(\frac{a^\varsigma - b^\varsigma}{\varsigma\log(a / b)}\right)^{1 / \varsigma} & \rho = 0, \varsigma \neq 0, a \neq b \\ +\frac{1}{\exp(1 / \rho)} \left(\frac{a^{a^\rho}}{b^{b^\rho}}\right)^{1 / (a^\rho - b^\rho)} & \rho = \varsigma \neq 0, a \neq b \\ +\sqrt{ab} & \rho = \varsigma = 0, a \neq b \\ +a & a = b. +\end{cases}$$ +The extended mean reduces to the logarithmic mean when either $\rho = 0$ and $\varsigma = 1$, or $\rho = 1$ and $\varsigma = 0$. But using the extended mean in place of the logarithmic mean allows for decompositions of indexes based on other types of means, like harmonic indexes ($\rho = -1$) and the Lloyd-Moulton index ($\rho = 1 - \sigma$, where $\sigma$ is an elasticity of substitution). + +The key to transforming the weights in a generalized mean of order $\rho$ into the weights for a generalized mean of order $\varsigma$ comes from noting that the extended mean is always strictly positive and satisfies the identity +$$\begin{align} +\sum_{i=1}^{n} w_{i} \mathfrak{E}_{\rho\varsigma}(r_i, \mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}))^{\rho - \varsigma} \varepsilon_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) \equiv 0,\label{eq:identity} +\end{align}$$ +where +$$\varepsilon_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) = +\begin{cases} +r_i^\varsigma - \mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w})^\varsigma & \text{if } \varsigma \neq 0, \\ +\log(r_i) - \log(\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w})) & \text{if } \varsigma = 0. +\end{cases}$$ +@eqn:identity uses the extended mean to keep the weighted deviation from the mean constant for each price relative (up to a common factor of proportionality) when changing the order of the mean from $\rho$ to $\varsigma$, without changing the value of the mean. Rearranging then gives that +$$\begin{align} +v_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) = w_{i} \mathfrak{E}_{\rho\varsigma}(r_i, \mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}))^{\rho - \varsigma} \Bigg/ \sum_{j=1}^{n} w_{j} \mathfrak{E}_{\rho\varsigma}(r_j, \mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}))^{\rho - \varsigma}\label{eq:res1} +\end{align}$$ +is a suitable function to find weights that turn an index based on a generalized mean of order $\rho$ into one based on a generalized mean of order $\varsigma$. + +The function given by @eqn:res1 takes on all existing decompositions that I know of as special cases. Setting $\rho = 0$ and $\varsigma = 1$, or $\rho = 1$ and $\varsigma = 0$, gives the special cases by Balk (2008) and Reinsdorf et al. (2002) for decomposing indexes based on arithmetic and geometric means (because the extended mean reduces to the logarithmic mean). Similarly, because $\mathfrak{E}_{\rho\varsigma}(r_i, \mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}))^{\rho - \varsigma} \equiv \left(\mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}) r_{i}\right)^\rho$ when $\rho = -1$ and $\varsigma = 1$, or $\rho = 1$ and $\varsigma = -1$, setting $\rho = -1$ and $\varsigma = 1$ reduces @eqn:res1 to +$$v_{i}(\mathbf{r}, \mathbf{w}; -1, 1) = \frac{w_{i} / r_{i}}{\sum_{i=1}^{n}w_{i} / r_{i}} ;$$ +if $\mathbf{w}$ is a vector of current-period expenditure/revenue shares then these are the hybrid weights that allow a Paasche index to be calculated as an arithmetic mean of price relatives. Setting $\rho = 1$ and $\varsigma = -1$ reduces @eqn:res1 to +$$v_{i}(\mathbf{r}, \mathbf{w}; 1, -1) = \frac{w_{i} r_{i}}{\sum_{i=1}^{n}w_{i} r_{i}}.$$ +If $\mathbf{w}$ is a vector of base-period expenditure/revenue shares then these are the hybrid weights that allow a Laspeyres index to be calculated as a harmonic mean of price relatives. As should be expected, the weights are unchanged if $\rho = \varsigma$ or each element of $\mathbf{r}$ takes on the same value. + +### Transitivity, monotonicity, and uniqueness + +The extended mean has two properties that make it useful for decomposing price indexes. First, the order of the extended mean has a transitivity property under multiplication: $\mathfrak{E}_{\rho\varsigma}(a, b)^{\rho - \varsigma} = \mathfrak{E}_{\rho\tau}(a, b)^{\rho - \tau}\mathfrak{E}_{\tau\varsigma}(a, b)^{\tau - \varsigma}$. This means the function in @eqn:res1 is transitivity, such that transmuting the weights to turn a generalized mean of order $\rho$ into a generalized mean of order $\tau$, and then transmuting these weights again to turn a generalized mean of order $\tau$ into a generalized mean of order $\varsigma$, is the same as finding weights to make a generalized mean of order $\rho$ into one of $\varsigma$. That is, +$$\mathbf{v}(\mathbf{r}, \mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \tau); \tau, \varsigma) \equiv \mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \varsigma).$$ +As will be seen later, not all decompositions have this property. + +Second, the extended mean is a strictly increasing function in both arguments (Bullen, 2003, p. 395). This means that the function in @eqn:res1 has a monotonicity property whereby the transmuted weights increase (decrease) for large (small) price relatives if and only if $\rho > \varsigma$. That is, assuming $\mathbf{r}$ is ordered from smallest to largest (and does not contain all the same value), if $\rho > \varsigma$ then there is a pair of integer $k,l$, with $k\leq l$, such that $v_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) \geq w_{i}$ for $i\geq l$ and $v_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) \leq w_{i}$ for $i\leq k$, with these equalities reversed if $\rho < \varsigma$.[^2] Again, not all decompositions satisfy this property. + +[^2]: These are weak inequalities to account for the case that some weights are 0. If the vector if weights is strictly positive then the inequalities are strict. + +The decomposition given by @eqn:res1 is unique when $n = 2$ and $r_{1} \neq r_{2}$, and is the only such function that always returns $\mathbf{w}$ when $r_{1} = r_{2}$. But @eqn:res1 is necessarily not unique when $n\geq3$, and there are infinitely many ways to decompose an index based on the generalized mean.[^3] Nonetheless, the limited case of uniqueness will be useful in @sec:superlative. + +[^3]: Take, for example, (1/2, 1, 3/2) with weights (1/6, 1/3, 1/2). The weighted harmonic mean is 1, which can be computed as an arithmetic mean with weights (1/3, 1/3, 1/3) or (1/4, 1/2, 1/4). Hence there are multiple additive decompositions for the harmonic mean. + +### Numerical example + +Consider the following numerical example for decomposing a quadratic-mean index (von der lippe, 2007, p. 61) (i.e., a producer price index with an elasticity of substitution of -1) made using the price and quantity data from Balk (2008, tab. 3.1--3.2). The `transmute_weights()` function parameterizes the decomposition in @eqn:res1 to make a function that decomposes any generalized-mean index. + +```{r} +library(piar) + +p2 <- c(1.2, 3, 1.3, 0.7, 1.4, 0.8) +p1 <- 1 +q2 <- c(0.8, 0.9, 1.9, 1.3, 4.7, 0.6) +q1 <- c(1, 1, 2, 1, 4.5, 0.5) + +rel <- p2 / p1 + +s1 <- scale_weights(p1 * q1) +s2 <- scale_weights(p2 * q2) + +v <- transmute_weights(rel, s1, order = 2) + +all.equal(gmean(rel, s1, order = 2), gmean(rel, v)) +``` + +Because the quadratic mean is larger than the arithmetic mean, the weight from the smaller price relatives is transferred to the largest price relative. + +```{r} +(v - s1)[order(rel)] +``` + +It is also readily seen that turning the arithmetic decomposition into a geometric one is the same as directly constructing the multiplicative decomposition. + +```{r} +all.equal( + transmute_weights(rel, v, order = 1, to = 0), + transmute_weights(rel, s1, order = 2, to = 0) +) +``` + +## Extensions + +### Decomposing superlative indexes {#sec:superlative} + +The additive and multiplicative decompositions for the Fisher index by Reinsdorf et al. (2002, sec. 6) can be generalized in the same way as the decompositions for the arithmetic and geometric indexes by noting that the Fisher index is simply a nested generalized mean of indexes based on the generalized mean. For a pair of generalized means $\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2})=\left(\mathfrak{M}_{\rho_1}(\mathbf{r}, \mathbf{w}_1), \mathfrak{M}_{\rho_2}(\mathbf{r}, \mathbf{w}_2)\right)$ mapping into $\mathbb{R}_2^{++}$ with weights $\mathbf{\omega}=(\omega_1, \omega_2) \in \Delta^1$, an index based on nested generalized means is written as +$$\begin{align} +\mathfrak{M}_{\rho}\left(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}\right). \label{eq:superlative} +\end{align}$$ + +The general family of superlative quadratic mean indexes of order $\tau$ comes from setting $\rho = 0$, $\rho_1 = \tau / 2$, and $\rho_2 = -\tau / 2$ when $\omega_1 = \omega_2 = 1 / 2$, $\mathbf{w}_1$ are base-period expenditure/revenue shares, and $\mathbf{w}_2$ are current-period expenditure/revenue shares. In particular, setting $\tau = 2$ gives the Fisher index and setting $\tau = 1$ gives the implicit Walsh index. But @eqn:superlative covers other types of indexes as well; for example, setting each element of $\mathbf{w}_1$ and $\mathbf{w}_2$ to $1 / n$ when $\tau = 2$ gives the Carruthers-Sellwood-Ward-Dalén index that serves as an estimator for the Fisher index, whereas $\tau = 1$ gives the Balk-Walsh index. Setting $\rho = -1$ gives the harmonic analogue of the Fisher index, which is not a superlative quadratic mean indexes of order $\tau$. Finally, setting $\rho = \rho_{1} = \rho_{2}$ and $\mathbf{w}_{1} = \mathbf{w}_{2}$ gives an index based on a generalized mean of order $\rho$, so that the decomposition of an index based on the generalized mean is a special case of the decomposition for @eqn:superlative. + +An index of the form in @eqn:superlative can be decomposed into an index based on the generalized mean of order $\rho$ using the weights in @eqn:res1, as it can be written as the generalized mean +$$\mathfrak{M}_{\rho}(\mathbf{r}, \omega_1 \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \rho) + \omega_2\mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \rho)).$$ +The transformation in @eqn:res1 then applies as before, just replacing $\mathbf{w}$ with the more complicated weights $\omega_1 \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \rho) + \omega_2\mathbf{v}(\mathbf{r}, \mathbf{w}_2, \rho_2, \rho)$, which can be written as +$$\begin{align} +\mathbf{v}(\mathbf{r}, \omega_1 \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \rho) + \omega_2\mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \rho); \rho, \varsigma). \label{eq:res2} +\end{align}$$ +The idea is to transmute the weights for both inner means to be of the same order as the outer mean ($\rho$) so that they can be added together, and then transmute these weights to represent the outer generalized mean as a mean of order $\varsigma$. Note that this means the decomposition satisfies the same transitivity property as @eqn:res1 with respect to $\rho$ and $\varsigma$. + +Continuing with the previous example, the `transmute_weights2()` function parameterizes the decomposition in @eqn:res2 and can be used to decompose the Fisher index. + +```{r} +v1 <- transmute_weights2(rel, list(s1, s2)) + +all.equal(nested_gmean(rel, list(s1, s2)), gmean(rel, v1)) + +all.equal( + v1, + transmute_weights( + rel, + transmute_weights2(rel, list(s1, s2), to = 2), + order = 2 + ) +) +``` + +An alternative approach to decompose @eqn:superlative is to generalize the (additive) van IJzeren decomposition for the Fisher index, which can be written as +$$\begin{align} +v_{1}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \varsigma) \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \varsigma) + v_{2}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \varsigma) \mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \varsigma).\label{eq:res3} +\end{align}$$ +Note that for a Fisher index, if $\varsigma=1$ then $\mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \varsigma)$ is a vector of base-period expenditure/revenue shares, $\mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \varsigma)$ is a vector of hybrid Paasche weights, and $\mathbf{v}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \varsigma)$ are the unique weights that decompose the geometric mean of the Laspeyres and Paasche indexes, which equals the van IJzeren decomposition. The idea here is to transmute the weights for both the inner and outer generalized means so that they are means of order $\varsigma$, then take the product of these weights. @eqn:res2 and @eqn:res3 generally give different decompositions, as the latter is not transitive, but reduce to @eqn:res1 when $\rho = \rho_{1} = \rho_{2}$ and $\mathbf{w}_{1} = \mathbf{w}_{2}$. + +These two approaches for decomposing @eqn:superlative can be generalized with a pivot value $\psi$ that acts as the link between the inner and outer generalized means. More generally, an index of the form in @eqn:superlative can be decomposed into a generalized mean of order $\rho$ with weights +$$\mathbf{v}(\mathbf{r},v_{1}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \psi) \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \psi) + v_{2}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \psi) \mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \psi); \psi, \varsigma).$$ +Setting $\psi=\rho$ gives @eqn:res2, whereas setting $\psi=\varsigma$ gives @eqn:res3. + +```{r} +v2 <- transmute_weights2(rel, list(s1, s2), pivot = 1) + +all.equal(nested_gmean(rel, list(s1, s2)), gmean(rel, v2)) + +all.equal( + v2, + transmute_weights( + rel, + transmute_weights2(rel, list(s1, s2), to = 2, pivot = 1), + order = 2 + ) +) +``` + +Overall the difference between the two approaches tends to be small. + +```{r} +summary(v1 - v2) +``` + +### Decomposing aggregated indexes + +The decomposition in @eqn:res3 can be extended to get a decomposition for an index constructed using the usual two-step procedure to make a price index. If price relatives are partitioned into $k$ groups, and an index is made from $k$ sub-indexes $\mathfrak{N}_{\rho_{1}\ldots\rho_{k}}(\mathbf{r}, \mathbf{w}_{1}, \ldots, \mathbf{w}_{k}) = \left(\mathfrak{M}_{\rho_1}(\mathbf{r}_{1}, \mathbf{w}_{1}), \ldots, \mathfrak{M}_{\rho_k}(\mathbf{r}_{k}, \mathbf{w}_{k})\right)$ with weights $\mathbf{\omega}=(\omega_{1},\ldots,\omega_{k})$ as a generalized mean of order $\rho$, then +$$v_{i}(\mathfrak{N}_{\rho_{1}\ldots\rho_{k}}(\mathbf{r}, \mathbf{w}_{1}, \ldots, \mathbf{w}_{k}), \mathbf{\omega}; \rho, \varsigma) \mathbf{v}(\mathbf{r}_{i}, \mathbf{w}_i; \rho_{i}, \varsigma)$$ +decomposes how the components of the $i$-th sub-index contribute towards the total index. Concatenating each of these vectors of weights along with the vector of price relatives represents the nested mean over the partitioning of price relatives as a generalized mean of order $\varsigma$. + +```{r} +group <- rep(c("a", "b"), each = 3) + +s1_by_group <- split(s1, group) +rel_by_group <- split(rel, group) + +index_a <- gmean(rel_by_group$a, s1_by_group$a, order = 2) +index_b <- gmean(rel_by_group$b, order = 0) + +gmean(c(index_a, index_b), sapply(s1_by_group, sum), order = 2) + +decomp_a <- transmute_weights(rel_by_group$a, s1_by_group$a, order = 2) +decomp_b <- transmute_weights(rel_by_group$b, order = 0) + +v <- Map( + `*`, + transmute_weights(c(index_a, index_b), sapply(s1_by_group, sum), order = 2), + list(decomp_a, decomp_b) +) |> + unlist() + +gmean(rel, v) +``` + +This approach to decomposing aggregate indexes also has the benefit that contributions for different groups can be made using different methods and combined in a way that decomposes the aggregated index. For example, the percent-change decomposition by Diewert (2002) can be used to decompose the Fisher index for one group, whereas percent-change contributions from the additive decomposition of a Jevons index can be used to decompose another group, and combined in a consistent way to get percent-change contributions for the aggregated index. + +### Decomposing deflators {#sec:harmonic} + +The decomposition in @eqn:res1 can be used to construct a decomposition for how a price index deflates a change in aggregate value over time to get a quantity index. Letting $V$ be the change in total value between two periods, the implicit quantity index for a price index based on the generalized mean of order $\rho$ is + +$$ +\frac{V}{\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w})}. +$$ + +Using @eqn:res1 to find weights to represent $\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w})$ as a harmonic mean means that +$$V/ \mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) \equiv \mathfrak{M}_{\varsigma}(V / \mathbf{r}, \mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, -\varsigma)),$$ +where $V / \mathbf{r} = \left(V / r_{1}, \ldots, V / r_{n}\right)$. + +Setting $\varsigma=1$ then gives an additive decomposition for how each price relative acts to deflate the change in total value over time, while setting $\varsigma=0$ gives a multiplicative decomposition. The same holds true when deflating with an index based on nested means, using either @eqn:res2 or @eqn:res3. + +```{r} +V <- sum(p2 * q2) / sum(p1 * q1) + +v <- transmute_weights2(rel, list(s1, s2), to = -1) + +all.equal( + gmean(V / rel, v), + nested_gmean(q2 / q1, list(s1, s2)) +) + +V / rel * v +``` + +### Decomposing contra-harmonic indexes + +von der Lippe (2015) discusses using the contra-harmonic mean (or antiharmonic as he calls it), a special case of the Lehmer mean (Bullen, 2003, p. 245) (of order 2), to make price indexes. + +```{r} +contraharmonic_mean <- function(x, weights, order) { + gmean(x, weights * x) +} + +# Arithmetic hybrid index +all.equal( + gmean(p2 / p1, p2 * q1), + contraharmonic_mean(p2 / p1, p1 * q1) +) + +# Palgrave index +all.equal( + gmean(p2 / p1, p2 * q2), + contraharmonic_mean(p2 / p1, p1 * q2) +) +``` + +The Lehmer mean of order $\rho$ is simply the arithmetic mean of the with weights +$$\left(w_{1}r_{1}^{\rho - 1}, \ldots, w_{n}r_{n}^{\rho - 1}\right) / \sum_{i = 1}^{n} w_{i} r_{i}^{\rho - 1},$$ +and so indexes based on these means can be decomposed with @eqn:res1 by using the these weights instead of $\mathbf{w}$. + +## References {-} + +Balk, B. M. (2008). _Price and Quantity Index Numbers_. Cambridge University Press. https://doi.org/10.1017/CBO9780511720758. + +Bullen, P. S. (2003). _Handbook of Means and their Inequalities_. Springer Science+Business Media. https://doi.org/10.1007/978-94-017-0399-4. + +Diewert, W. E. (2002). The quadratic approximation lemma and decompositions of superlative indexes. _Journal of Economic and Social Measurement_, 28(1-2): 63--88. https://doi.org/10.3233/JEM-2003-0200. + +Färe, R., Karagiannis, G. (2025). An alternative derivation of the van IJzeren weights and some new results for the additive decomposition of Fisher indices. _Journal of Productivity Analysis_, 64(3): 363--377. https://doi.org/10.1007/s11123-025-00774-2. + +Hallerbach, W. G. (2005). An alternative decomposition of the Fisher index. _Economics Letters_, 86(2): 147--152. https://doi.org/10.1016/j.econlet.2004.07.008. + +Lent, J., Dorfman, A. H. (2009). Using a weighted average of base period price indexes to approximate a superlative index. _Journal of Official Statistics_, 25(1): 149--149. + +Martin, S. (2021). A note on generalized decompositions for price indexes. _Prices Analyical Series_, Statistics Canada. + +Martin, S. (2026). A note on the additive decomposition of GEKS indexes. _Journal of Official Statistics_, 0282423X261451318. https://doi.org/10.1177/0282423X261451318. + +Reinsdorf, M. B., Diewert, W. E., Ehemann, C. (2002). Additive decompositions for Fisher, Törnqvist and geometric mean indexes. _Journal of Economic and Social Measurement_, 28(1--2): 51--61. https://doi.org/10.3233/JEM-2003-0194. + +von der Lippe, P. (2007). _Index Theory and Price Statistics_. Peter Lang. https://doi.org/10.3726/978-3-653-01120-3. + +von der Lippe, P. (2015). _Generalized Statistical Means and New Price Index Formulas, Notes on some unexplored index formulas, their interpretations and generalizations_. Munich Personal RePEc Archive paper no. 64952. + +Webster, M. B., Tarnow-Mordi, R. C. (2019). _Decomposing multilateral price indexes into the contributions of individual commodities_. Journal of Official Statistics, 35(2): 461--486. https://doi.org/10.2478/jos-2019-0020. diff --git a/vignettes/decomposing-indexes.qmd b/vignettes/decomposing-indexes.qmd deleted file mode 100644 index 34bf1f80..00000000 --- a/vignettes/decomposing-indexes.qmd +++ /dev/null @@ -1,305 +0,0 @@ ---- -title: "Decomposing price indexes" -format: - html: - html-math-method: mathjax -vignette: > - %\VignetteIndexEntry{Decomposing price indexes} - %\VignetteEngine{quarto::html} - %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' -bibliography: ref.bib -bibliographystyle: apalike ---- - -*This vignette presents an extended version of @martin2021, and shows how to use the tools in this package to make these decompositions.* - -It is often useful to be able to decompose a price index into an additive or multiplicative form to evaluate how each input to the index affects its value. Following @balk2008, a price index is said to admit an additive decomposition if there exist weights that allow it to be represented as an arithmetic mean of price relatives, and is said to admit a multiplicative decomposition if there are weights that allow it to be represented as a geometric mean. Switching prices for quantities gives the analogous statements for a quantity index, and nothing is lost by focusing on price indexes. - -There are several well-known decompositions for the most common types of bilateral price indexes. @balk2008[equation 4.13] gives an additive decomposition for any index based on the geometric mean by transmuting the weights in the geometric mean with the logarithmic mean. This is the same decomposition derived by @reinsdorf2002 [equation 20] for the Törnqvist index. A similar approach yields a multiplicative decomposition for any index based on the arithmetic mean, again using the logarithmic mean [@balk2008, equation 4.8]. Combining these results gives additive and multiplicative decompositions for the Fisher index [@reinsdorf2002, section 6]. The van IJzeren additive decomposition for the Fisher index [@balk2008, equation 4.18] is an alternative that does not explicitly use the logarithmic mean. Each of these decompositions results in weights that are positive and sum to one, as required to represent an index as an arithmetic or geometric mean.[^1] - -[^1]: There are decompositions with "weights" that do not sum to one, such as those for the Fisher index by @reinsdorf2002[section 2] and @hallerbach2005, and for other superlative indexes by @diewert2002. @balk2008 [equation 4.28] gives the original multiplicative decomposition of the Fisher index, due to Vartia, for which the weights also do not sum to one. @webster2019 consider several decompositions for multilateral indexes, although again the "weights" do not sum to one. - -I show how the additive and multiplicative decompositions for geometric, arithmetic, and Fisher indexes that use the logarithmic mean can be consolidated and made more general by switching out the logarithmic mean for the more general extended mean. The main result is a function that transmutes the weights in a generalized mean of a given order so that it can be represented as a generalized mean of any other order. This covers additive and multiplicative decompositions for indexes that do not belong to the arithmetic or geometric families, like harmonic indexes or the Lloyd-Moulton index, and allows both additive and multiplicative decompositions to be covered by a single equation, rather than treating them as different cases. Expressing a generalized index as a generalized mean of any other order also allows for the decomposition of indexes that are nested generalized means, like the family of superlative quadratic mean indexes that includes the Fisher index or the AG mean index by @lent2009. I demonstrate some useful properties of this general decomposition and show how it can be used to decompose indexes based on other types on means and decompose deflating a change in aggregate values with a price index. See @martin2026 for an application of these methods to multilateral indexes. Throughout I show how the tools in the *piar* package can be used to decompose a price index. - -## Decomposing generalized-mean indexes {#sec-decompose} - -A natural extension to the decompositions for indexes based on the arithmetic and geometric means is to derive weights that transform an index based on a generalized mean of order $\rho$ into one based on a generalized mean of order $\varsigma$. To fix notation, let $\mathbf{r} = (r_{1}, r_{2}, \ldots, r_{n}) \in \mathbb{R}^{n}_{++}$ be a vector of price relatives for $n\geq2$ products and let $\mathbf{w} = (w_{1}, w_{2}, \ldots, w_{n}) \in \Delta^{n - 1}$ be the corresponding weights, where $\Delta^{n - 1} = \{\mathbf{w} \in \mathbb{R}_{+}^{n} | \sum_{i = 1}^{n} w_{i} = 1\}$ is the unit simplex. The goal is to find a vector-valued function $$ -\mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) = (v_{1}(\mathbf{r}, \mathbf{w}; \rho, \varsigma), v_{2}(\mathbf{r}, \mathbf{w}; \rho, \varsigma),\ldots, v_{n}(\mathbf{r}, \mathbf{w}; \rho, \varsigma)) -$$ mapping into $\Delta^{n - 1}$ such that $$ -\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) \equiv \mathfrak{M}_{\varsigma}(\mathbf{r}, \mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \varsigma)), -$$ where $\mathfrak{M}_{\rho}$ is the generalized mean $$ -\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) = -\begin{cases} -\left(\sum_{i = 1}^{n} w_{i} r_i^{\rho}\right)^{1 / \rho} & \text{if } \rho \neq 0 \\ -\prod_{i = 1}^{n} r_{i}^{w_{i}} & \text{if } \rho = 0. -\end{cases} -$$ - -Setting $\varsigma = 1$ then yields an additive decomposition for any index based on a generalized mean of order $\rho$, such that $$ -\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) = \sum_{i=1}^{n} r_{i} v_i(\mathbf{r}, \mathbf{w}; \rho, 1), -$$ and setting $\varsigma = 0$ yields a multiplicative decomposition, such that $$ -\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) = \prod_{i=1}^{n} r_{i}^{ v_i(\mathbf{r}, \mathbf{w}; \rho, 0)}. -$$ Note that any index that admits an additive decomposition can be used to derive percent-change contributions for each price relative, $v_i(\mathbf{r}, \mathbf{w}; \rho, 1) (r_i - 1)$, that sum up to $\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) - 1$, although the converse is not true and it is possible to decompose an index into percent-change contributions that do not allow it to be represented as an arithmetic mean. Note also that other types of decompositions can be had by setting $\varsigma$ to a value other than 0 or 1; for example, setting $\varsigma = -1$ gives the harmonic decomposition [@fare2025], - -$$ -\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) = 1 / \left(\sum_{i=1}^{n} v_i(\mathbf{r}, \mathbf{w}; \rho, -1) / r_{i}\right), -$$ - -that will be useful in @sec-harmonic. - -@balk2008 and @reinsdorf2002 show how to derive $\mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \varsigma)$ when $\rho = 1$ and $\varsigma = 0$ (multiplicative decomposition of an arithmetic index) $$ -v_{i}(\mathbf{r}, \mathbf{w}; 1, 0) = \frac{w_{i} \mathfrak{L}(r_{i}, \mathfrak{M}_{1}(\mathbf{r}, \mathbf{w}))}{\sum_{j=1}^{n} w_{j} \mathfrak{L}(r_{j}, \mathfrak{M}_{1}(\mathbf{r}, \mathbf{w}))} -$$ and $\rho = 0$ and $\varsigma = 1$ (additive decomposition of a geometric index) $$ -v_{i}(\mathbf{r}, \mathbf{w}; 0, 1) = \frac{w_{i} / \mathfrak{L}(r_{i}, \mathfrak{M}_{0}(\mathbf{r}, \mathbf{w}))}{\sum_{j=1}^{n} w_{j} / \mathfrak{L}(r_{j}, \mathfrak{M}_{0}(\mathbf{r}, \mathbf{w}))}, -$$ using the logarithmic mean $$ -\mathfrak{L}(a, b) = -\begin{cases} -\frac{a - b}{\log(a / b)} & a \neq b\\ -a & a = b. -\end{cases} -$$ - -Generalizing these results follows from replacing the logarithmic mean with the more general extended mean [@bullen2003, page 393], defined for any $a,b > 0$ as $$ -\mathfrak{E}_{\rho\varsigma}(a, b) = -\begin{cases} -\left(\frac{\varsigma(a^\rho - b^\rho)}{\rho(a^\varsigma - b^\varsigma)}\right)^{1 / (\rho - \varsigma)} & \rho \neq \varsigma, \rho \neq 0, \varsigma \neq 0, a \neq b \\ -\left(\frac{a^\rho - b^\rho}{\rho\log(a / b)}\right)^{1 / \rho} & \rho \neq 0, \varsigma = 0, a \neq b \\ -\left(\frac{a^\varsigma - b^\varsigma}{\varsigma\log(a / b)}\right)^{1 / \varsigma} & \rho = 0, \varsigma \neq 0, a \neq b \\ -\frac{1}{\exp(1 / \rho)} \left(\frac{a^{a^\rho}}{b^{b^\rho}}\right)^{1 / (a^\rho - b^\rho)} & \rho = \varsigma \neq 0, a \neq b \\ -\sqrt{ab} & \rho = \varsigma = 0, a \neq b \\ -a & a = b. -\end{cases} -$$ The extended mean reduces to the logarithmic mean when either $\rho = 0$ and $\varsigma = 1$, or $\rho = 1$ and $\varsigma = 0$. But using the extended mean in place of the logarithmic mean allows for decompositions of indexes based on other types of means, like harmonic indexes ($\rho = -1$) and the Lloyd-Moulton index ($\rho = 1 - \sigma$, where $\sigma$ is an elasticity of substitution). - -The key to transforming the weights in a generalized mean of order $\rho$ into the weights for a generalized mean of order $\varsigma$ comes from noting that the extended mean is always strictly positive and satisfies the identity $$ -\sum_{i=1}^{n} w_{i} \mathfrak{E}_{\rho\varsigma}(r_i, \mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}))^{\rho - \varsigma} \varepsilon_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) \equiv 0, -$$ {#eq-identity} where $$ -\varepsilon_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) = -\begin{cases} -r_i^\varsigma - \mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w})^\varsigma & \text{if } \varsigma \neq 0, \\ -\log(r_i) - \log(\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w})) & \text{if } \varsigma = 0. -\end{cases} -$$ @eq-identity uses the extended mean to keep the weighted deviation from the mean constant for each price relative (up to a common factor of proportionality) when changing the order of the mean from $\rho$ to $\varsigma$, without changing the value of the mean. Rearranging then gives that $$ -v_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) = w_{i} \mathfrak{E}_{\rho\varsigma}(r_i, \mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}))^{\rho - \varsigma} \Bigg/ \sum_{j=1}^{n} w_{j} \mathfrak{E}_{\rho\varsigma}(r_j, \mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}))^{\rho - \varsigma} -$$ {#eq-res1} is a suitable function to find weights that turn an index based on a generalized mean of order $\rho$ into one based on a generalized mean of order $\varsigma$. - -The function given by @eq-res1 takes on all existing decompositions that I know of as special cases. Setting $\rho = 0$ and $\varsigma = 1$, or $\rho = 1$ and $\varsigma = 0$, gives the special cases by @balk2008 and @reinsdorf2002 for decomposing indexes based on arithmetic and geometric means (because the extended mean reduces to the logarithmic mean). Similarly, because $\mathfrak{E}_{\rho\varsigma}(r_i, \mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}))^{\rho - \varsigma} \equiv \left(\mathfrak{M}_{\rho} (\mathbf{r}, \mathbf{w}) r_{i}\right)^\rho$ when $\rho = -1$ and $\varsigma = 1$, or $\rho = 1$ and $\varsigma = -1$, setting $\rho = -1$ and $\varsigma = 1$ reduces @eq-res1 to $$ -v_{i}(\mathbf{r}, \mathbf{w}; -1, 1) = \frac{w_{i} / r_{i}}{\sum_{i=1}^{n}w_{i} / r_{i}} ; -$$ if $\mathbf{w}$ is a vector of current-period expenditure/revenue shares then these are the hybrid weights that allow a Paasche index to be calculated as an arithmetic mean of price relatives. Setting $\rho = 1$ and $\varsigma = -1$ reduces @eq-res1 to $$ -v_{i}(\mathbf{r}, \mathbf{w}; 1, -1) = \frac{w_{i} r_{i}}{\sum_{i=1}^{n}w_{i} r_{i}}. -$$ If $\mathbf{w}$ is a vector of base-period expenditure/revenue shares then these are the hybrid weights that allow a Laspeyres index to be calculated as a harmonic mean of price relatives. As should be expected, the weights are unchanged if $\rho = \varsigma$ or each element of $\mathbf{r}$ takes on the same value. - -### Transitivity, monotonicity, and uniqueness - -The extended mean has two properties that make it useful for decomposing price indexes. First, the order of the extended mean has a transitivity property under multiplication: $\mathfrak{E}_{\rho\varsigma}(a, b)^{\rho - \varsigma} = \mathfrak{E}_{\rho\tau}(a, b)^{\rho - \tau}\mathfrak{E}_{\tau\varsigma}(a, b)^{\tau - \varsigma}$. This means the function in @eq-res1 is transitivity, such that transmuting the weights to turn a generalized mean of order $\rho$ into a generalized mean of order $\tau$, and then transmuting these weights again to turn a generalized mean of order $\tau$ into a generalized mean of order $\varsigma$, is the same as finding weights to make a generalized mean of order $\rho$ into one of $\varsigma$. That is, $$ -\mathbf{v}(\mathbf{r}, \mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \tau); \tau, \varsigma) \equiv \mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, \varsigma). -$$ As will be seen later, not all decompositions have this property. - -Second, the extended mean is a strictly increasing function in both arguments [@bullen2003, page 395]. This means that the function in @eq-res1 has a monotonicity property whereby the transmuted weights increase (decrease) for large (small) price relatives if and only if $\rho > \varsigma$. That is, assuming $\mathbf{r}$ is ordered from smallest to largest (and does not contain all the same value), if $\rho > \varsigma$ then there is a pair of integer $k,l$, with $k\leq l$, such that $v_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) \geq w_{i}$ for $i\geq l$ and $v_{i}(\mathbf{r}, \mathbf{w}; \rho, \varsigma) \leq w_{i}$ for $i\leq k$, with these equalities reversed if $\rho < \varsigma$.[^2] Again, not all decompositions satisfy this property. - -[^2]: These are weak inequalities to account for the case that some weights are 0. If the vector if weights is strictly positive then the inequalities are strict. - -The decomposition given by @eq-res1 is unique when $n = 2$ and $r_{1} \neq r_{2}$, and is the only such function that always returns $\mathbf{w}$ when $r_{1} = r_{2}$. But @eq-res1 is necessarily not unique when $n\geq3$, and there are infinitely many ways to decompose an index based on the generalized mean.[^3] Nonetheless, the limited case of uniqueness will be useful in @sec-superlative. - -[^3]: Take, for example, (1/2, 1, 3/2) with weights (1/6, 1/3, 1/2). The weighted harmonic mean is 1, which can be computed as an arithmetic mean with weights (1/3, 1/3, 1/3) or (1/4, 1/2, 1/4). Hence there are multiple additive decompositions for the harmonic mean. - -### Numerical example - -Consider the following numerical example of decomposing a quadratic-mean index [@vonderlippe2007, page 61] (i.e., a producer price index with an elasticity of substitution of -1) made using the price and quantity data from @balk2008 [tables 3.1 and 3.2]. The `transmute_weights()` function parameterizes the decomposition in @eq-res1 to make a function that decomposes any generalized-mean index. - -```{r} -library(piar) - -p2 <- c(1.2, 3, 1.3, 0.7, 1.4, 0.8) -p1 <- 1 -q2 <- c(0.8, 0.9, 1.9, 1.3, 4.7, 0.6) -q1 <- c(1, 1, 2, 1, 4.5, 0.5) - -rel <- p2 / p1 - -s1 <- scale_weights(p1 * q1) -s2 <- scale_weights(p2 * q2) - -v <- transmute_weights(rel, s1, order = 2) - -all.equal(gmean(rel, s1, order = 2), gmean(rel, v)) -``` - -Because the quadratic mean is larger than the arithmetic mean, the weight from the smaller price relatives is transferred to the largest price relative. - -```{r} -(v - s1)[order(rel)] -``` - -It is also readily seen that turning the arithmetic decomposition into a geometric one is the same as directly constructing the multiplicative decomposition. - -```{r} -all.equal( - transmute_weights(rel, v, order = 1, to = 0), - transmute_weights(rel, s1, order = 2, to = 0) -) -``` - -## Extensions - -### Decomposing superlative indexes {#sec-superlative} - -The additive and multiplicative decompositions for the Fisher index by @reinsdorf2002 [section 6] can be generalized in the same way as the decompositions for the arithmetic and geometric indexes by noting that the Fisher index is simply a nested generalized mean of indexes based on the generalized mean. For a pair of generalized means $\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2})=\left(\mathfrak{M}_{\rho_1}(\mathbf{r}, \mathbf{w}_1), \mathfrak{M}_{\rho_2}(\mathbf{r}, \mathbf{w}_2)\right)$ mapping into $R_2^{++}$ with weights $\mathbf{\omega}=(\omega_1, \omega_2) \in \Delta^1$, an index based on nested generalized means is written as $$ -\mathfrak{M}_{\rho}\left(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}\right). -$$ {#eq-superlative} - -The general family of superlative quadratic mean indexes of order $\tau$ comes from setting $\rho = 0$, $\rho_1 = \tau / 2$, and $\rho_2 = -\tau / 2$ when $\omega_1 = \omega_2 = 1 / 2$, $\mathbf{w}_1$ are base-period expenditure/revenue shares, and $\mathbf{w}_2$ are current-period expenditure/revenue shares. In particular, setting $\tau = 2$ gives the Fisher index and setting $\tau = 1$ gives the implicit Walsh index. But @eq-superlative covers other types of indexes as well; for example, setting each element of $\mathbf{w}_1$ and $\mathbf{w}_2$ to $1 / n$ when $\tau = 2$ gives the Carruthers-Sellwood-Ward-Dalén index that serves as an estimator for the Fisher index, whereas $\tau = 1$ gives the Balk-Walsh index. Setting $\rho = -1$ gives the harmonic analogue of the Fisher index, which is not a superlative quadratic mean indexes of order $\tau$. Finally, setting $\rho = \rho_{1} = \rho_{2}$ and $\mathbf{w}_{1} = \mathbf{w}_{2}$ gives an index based on a generalized mean of order $\rho$, so that the decomposition of an index based on the generalized mean is a special case of the decomposition for @eq-superlative. - -An index of the form in @eq-superlative can be decomposed into an index based on the generalized mean of order $\rho$ using the weights in @eq-res1, as it can be written as the generalized mean $$ -\mathfrak{M}_{\rho}(\mathbf{r}, \omega_1 \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \rho) + \omega_2\mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \rho)). -$$ The transformation in @eq-res1 then applies as before, just replacing $\mathbf{w}$ with the more complicated weights $\omega_1 \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \rho) + \omega_2\mathbf{v}(\mathbf{r}, \mathbf{w}_2, \rho_2, \rho)$, which can be written as $$ -\mathbf{v}(\mathbf{r}, \omega_1 \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \rho) + \omega_2\mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \rho); \rho, \varsigma). -$$ {#eq-res2} The idea is to transmute the weights for both inner means to be of the same order as the outer mean ($\rho$) so that they can be added together, and then transmute these weights to represent the outer generalized mean as a mean of order $\varsigma$. Note that this means the decomposition satisfies the same transitivity property as @eq-res1 with respect to $\rho$ and $\varsigma$. - -Continuing with the previous example, the `transmute_weights2()` function parameterizes the decomposition in @eq-res2 and can be used to decompose the Fisher index. - -```{r} -v1 <- transmute_weights2(rel, list(s1, s2)) - -all.equal(nested_gmean(rel, list(s1, s2)), gmean(rel, v1)) - -all.equal( - v1, - transmute_weights( - rel, - transmute_weights2(rel, list(s1, s2), to = 2), - order = 2 - ) -) -``` - -An alternative approach to decompose @eq-superlative is to generalize the (additive) van IJzeren decomposition for the Fisher index, which can be written as $$ -v_{1}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \varsigma) \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \varsigma) + v_{2}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \varsigma) \mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \varsigma). -$$ {#eq-res3} Note that for a Fisher index, if $\varsigma=1$ then $\mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \varsigma)$ is a vector of base-period expenditure/revenue shares, $\mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \varsigma)$ is a vector of hybrid Paasche weights, and $\mathbf{v}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \varsigma)$ are the unique weights that decompose the geometric mean of the Laspeyres and Paasche indexes, which equals the van IJzeren decomposition. The idea here is to transmute the weights for both the inner and outer generalized means so that they are means of order $\varsigma$, then take the product of these weights. @eq-res2 and @eq-res3 generally give different decompositions, as the latter is not transitive, but reduce to @eq-res1 when $\rho = \rho_{1} = \rho_{2}$ and $\mathbf{w}_{1} = \mathbf{w}_{2}$. - -These two approaches for decomposing @eq-superlative can be generalized with a pivot value $\psi$ that acts as the link between the inner and outer generalized means. More generally, an index of the form in @eq-superlative can be decomposed into a generalized mean of order $\rho$ with weights -$$\mathbf{v}(\mathbf{r}, -v_{1}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \psi) \mathbf{v}(\mathbf{r}, \mathbf{w}_1; \rho_1, \psi) + v_{2}(\mathfrak{N}_{\rho_{1}\rho_{2}}(\mathbf{r}, \mathbf{w}_{1}, \mathbf{w}_{2}), \mathbf{\omega}; \rho, \psi) \mathbf{v}(\mathbf{r}, \mathbf{w}_2; \rho_2, \psi); \psi, \varsigma). -$$ Setting $\psi=\rho$ gives @eq-res2, whereas setting $\psi=\varsigma$ gives @eq-res3. - -```{r} -v2 <- transmute_weights2(rel, list(s1, s2), pivot = 1) - -all.equal(nested_gmean(rel, list(s1, s2)), gmean(rel, v2)) - -all.equal( - v2, - transmute_weights( - rel, - transmute_weights2(rel, list(s1, s2), to = 2, pivot = 1), - order = 2 - ) -) -``` - -Overall the difference between the two approaches tends to be small. - -```{r} -summary(v1 - v2) -``` - -### Decomposing aggregated indexes - -The decomposition in @eq-res3 can be extended to get a decomposition for an index constructed using the usual two-step procedure to make a price index. If price relatives are partitioned into $k$ groups, and an index is made from $k$ sub-indexes $\mathfrak{N}_{\rho_{1}\ldots\rho_{k}}(\mathbf{r}, \mathbf{w}_{1}, \ldots, \mathbf{w}_{k}) = \left(\mathfrak{M}_{\rho_1}(\mathbf{r}_{1}, \mathbf{w}_{1}), \ldots, \mathfrak{M}_{\rho_k}(\mathbf{r}_{k}, \mathbf{w}_{k})\right)$ with weights $\mathbf{\omega}=(\omega_{1},\ldots,\omega_{k})$ as a generalized mean of order $\rho$, then - -$$ -v_{i}(\mathfrak{N}_{\rho_{1}\ldots\rho_{k}}(\mathbf{r}, \mathbf{w}_{1}, \ldots, \mathbf{w}_{k}), \mathbf{\omega}; \rho, \varsigma) \mathbf{v}(\mathbf{r}_{i}, \mathbf{w}_i; \rho_{i}, \varsigma) -$$ - -decomposes how the components of the $i$-th sub-index contribute towards the total index. Concatenating each of these vectors of weights along with the vector of price relatives represents the nested mean over the partitioning of price relatives as a generalized mean of order $\varsigma$. - -```{r} -group <- rep(c("a", "b"), each = 3) - -s1_by_group <- split(s1, group) -rel_by_group <- split(rel, group) - -index_a <- gmean(rel_by_group$a, s1_by_group$a, order = 2) -index_b <- gmean(rel_by_group$b, order = 0) - -gmean(c(index_a, index_b), sapply(s1_by_group, sum), order = 2) - -decomp_a <- transmute_weights(rel_by_group$a, s1_by_group$a, order = 2) -decomp_b <- transmute_weights(rel_by_group$b, order = 0) - -v <- Map( - `*`, - transmute_weights(c(index_a, index_b), sapply(s1_by_group, sum), order = 2), - list(decomp_a, decomp_b) -) |> - unlist() - -gmean(rel, v) -``` - -This approach to decomposing aggregate indexes also has the benefit that contributions for different groups can be made using different methods and combined in a way that decomposes the aggregated index. For example, the percent-change decomposition by @diewert2002 can be used to decompose the Fisher index for one group, whereas percent-change contributions from the additive decomposition of a Jevons index can be used to decompose another group, and combined in a consistent way to get percent-change contributions for the aggregated index. - -### Decomposing deflators {#sec-harmonic} - -The decomposition in @eq-res1 can be used to construct a decomposition for how a price index deflates a change in aggregate value over time to get a quantity index. Letting $V$ be the change in total value between two periods, the implicit quantity index for a price index based on the generalized mean of order $\rho$ is - -$$ -\frac{V}{\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w})}. -$$ - -Using @eq-res1 to find weights to represent $\mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w})$ as a harmonic mean means that - -$$ -V/ \mathfrak{M}_{\rho}(\mathbf{r}, \mathbf{w}) \equiv \mathfrak{M}_{\varsigma}(V / \mathbf{r}, \mathbf{v}(\mathbf{r}, \mathbf{w}; \rho, -\varsigma)), -$$ {#eq-res4} where $V / \mathbf{r} = \left(V / r_{1}, \ldots, V / r_{n}\right)$. - -Setting $\varsigma=1$ then gives an additive decomposition for how each price relative acts to deflate the change in total value over time, while setting $\varsigma=0$ gives a multiplicative decomposition. The same holds true when deflating with an index based on nested means, using either @eq-res2 or @eq-res3. - -```{r} -V <- sum(p2 * q2) / sum(p1 * q1) - -v <- transmute_weights2(rel, list(s1, s2), to = -1) - -all.equal( - gmean(V / rel, v), - nested_gmean(q2 / q1, list(s1, s2)) -) - -V / rel * v -``` - -### Decomposing contra-harmonic indexes - -@vonderlippe2015 discusses using the contra-harmonic mean (or antiharmonic as he calls it), a special case of the Lehmer mean [@bullen2003, page 245] (of order 2), to make price indexes. - -```{r} -contraharmonic_mean <- function(x, weights, order) { - gmean(x, weights * x) -} - -# Arithmetic hybrid index -all.equal( - gmean(p2 / p1, p2 * q1), - contraharmonic_mean(p2 / p1, p1 * q1) -) - -# Palgrave index -all.equal( - gmean(p2 / p1, p2 * q2), - contraharmonic_mean(p2 / p1, p1 * q2) -) -``` - -The Lehmer mean of order $\rho$ is simply the arithmetic mean of the with weights - -$$ -\left(w_{1}r_{1}^{\rho - 1}, \ldots, w_{n}r_{n}^{\rho - 1}\right) / \sum_{i = 1}^{n} w_{i} r_{i}^{\rho - 1}, -$$ - -and so indexes based on these means can be decomposed with @eq-res1 by using the these weights instead of $\mathbf{w}$. - -## References diff --git a/vignettes/imputation.qmd b/vignettes/imputation.Rmd similarity index 96% rename from vignettes/imputation.qmd rename to vignettes/imputation.Rmd index cf9abdab..fda4ef7d 100644 --- a/vignettes/imputation.qmd +++ b/vignettes/imputation.Rmd @@ -2,12 +2,8 @@ title: "Imputation" vignette: > %\VignetteIndexEntry{Imputation} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- The example in `vignette("piar")` used parental imputation to both diff --git a/vignettes/index-number-formulas.qmd b/vignettes/index-number-formulas.Rmd similarity index 98% rename from vignettes/index-number-formulas.qmd rename to vignettes/index-number-formulas.Rmd index 639687d9..5bb7485b 100644 --- a/vignettes/index-number-formulas.qmd +++ b/vignettes/index-number-formulas.Rmd @@ -2,18 +2,14 @@ title: "Index-number formulas" vignette: > %\VignetteIndexEntry{Index-number formulas} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- Price indexes based on a generalized mean of price relatives constitute a large family of bilateral index-number formulas that are consistent in aggregation, and any index based on the generalized mean can be used to -make and aggregate elementary indexes. See @sec-appendix for a comprehensive list. +make and aggregate elementary indexes. See the last section for a comprehensive list. To see how to make superlative indexes as well, let's start with a simple dataset of prices and quantities for two businesses over three periods. We'll be making diff --git a/vignettes/matrix-aggregation.qmd b/vignettes/matrix-aggregation.Rmd similarity index 96% rename from vignettes/matrix-aggregation.qmd rename to vignettes/matrix-aggregation.Rmd index 2dab31b0..97846b1f 100644 --- a/vignettes/matrix-aggregation.qmd +++ b/vignettes/matrix-aggregation.Rmd @@ -2,12 +2,8 @@ title: "Matrix aggregation" vignette: > %\VignetteIndexEntry{Matrix aggregation} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- Aggregating a price index can be done as a matrix operation. Although diff --git a/vignettes/multiple-baskets.qmd b/vignettes/multiple-baskets.Rmd similarity index 97% rename from vignettes/multiple-baskets.qmd rename to vignettes/multiple-baskets.Rmd index 728b8f74..3a76acb7 100644 --- a/vignettes/multiple-baskets.qmd +++ b/vignettes/multiple-baskets.Rmd @@ -2,12 +2,8 @@ title: "Aggregating across baskets" vignette: > %\VignetteIndexEntry{Aggregating across baskets} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- Most prices indexes use the same set of weights to aggregate elementary diff --git a/vignettes/multiple-data-sources.qmd b/vignettes/multiple-data-sources.Rmd similarity index 95% rename from vignettes/multiple-data-sources.qmd rename to vignettes/multiple-data-sources.Rmd index 9c9ba901..9d559113 100644 --- a/vignettes/multiple-data-sources.qmd +++ b/vignettes/multiple-data-sources.Rmd @@ -2,12 +2,8 @@ title: "Multiple sources of data" vignette: > %\VignetteIndexEntry{Multiple sources of data} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- Price indexes are usually made from several sources of data. An diff --git a/vignettes/multiple-dimensions.qmd b/vignettes/multiple-dimensions.Rmd similarity index 96% rename from vignettes/multiple-dimensions.qmd rename to vignettes/multiple-dimensions.Rmd index 00f490da..dbb12bcd 100644 --- a/vignettes/multiple-dimensions.qmd +++ b/vignettes/multiple-dimensions.Rmd @@ -2,12 +2,8 @@ title: "Aggregating across dimensions" vignette: > %\VignetteIndexEntry{Aggregating across dimensions} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- Price indexes are often aggregated over multiple dimensions. Matched diff --git a/vignettes/piar.qmd b/vignettes/piar.Rmd similarity index 98% rename from vignettes/piar.qmd rename to vignettes/piar.Rmd index 7ce99eff..8db70d69 100644 --- a/vignettes/piar.qmd +++ b/vignettes/piar.Rmd @@ -2,12 +2,8 @@ title: "Making price indexes" vignette: > %\VignetteIndexEntry{Making price indexes} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- Most price indexes are made with a two-step procedure, where diff --git a/vignettes/ref.bib b/vignettes/ref.bib deleted file mode 100644 index 7148150f..00000000 --- a/vignettes/ref.bib +++ /dev/null @@ -1,127 +0,0 @@ -@book{balk2008, - title = {Price and Quantity Index Numbers}, - author = {Balk, B. M.}, - year = {2008}, - publisher = {Cambridge University Press}, - doi={10.1017/CBO9780511720758} -} - -@book{bullen2003, - title = {Handbook of Means and their Inequalities}, - author = {Bullen, P. S.}, - year = {2003}, - publisher = {Springer Science+Business Media}, - doi = {10.1007/978-94-017-0399-4} -} - -@book{cpimanual, - title = {Consumer price index manual: Theory and practice}, - author = {ILO, and IMF, and OECD, and Eurostat, and UN, and World Bank}, - year = {2004}, - publisher = {International Monetary Fund}, - doi = {10.5089/9781484354841.069} -} - -@article{hallerbach2005, - title = {An alternative decomposition of the {F}isher index}, - author = {Hallerbach, W. G.}, - journal = {Economics Letters}, - volume = {86}, - number = {2}, - pages = {147--152}, - year = {2005}, - doi = {10.1016/j.econlet.2004.07.008} -} - -@article{reinsdorf2002, - title = {Additive decompositions for {F}isher, {T\"o}rnqvist and geometric mean indexes}, - author = {Reinsdorf, M. B. and Diewert, W. E. and Ehemann, C.}, - journal = {Journal of Economic and Social Measurement}, - volume = {28}, - number = {1-2}, - pages = {51--61}, - year = {2002}, - doi = {10.3233/JEM-2003-0194} -} - -@book{ppimanual, - title = {Producer price index manual: Theory and practice}, - author = {ILO, and IMF, and OECD, and Eurostat, and UN, and World Bank}, - year = {2004}, - publisher = {International Monetary Fund}, - doi = {10.5089/9781589063044.069} -} - -@article{diewert2002, - title = {The quadratic approximation lemma and decompositions of superlative indexes}, - author = {Diewert, W. E.}, - journal = {Journal of Economic and Social Measurement}, - year = {2002}, - volume = {28}, - number = {1-2}, - pages = {63--88}, - doi = {10.3233/JEM-2003-0200} -} - -@article{lent2009, - title = {Using a weighted average of base period price indexes to approximate a superlative index}, - author = {Lent, J. and Dorfman, A. H.}, - journal = {Journal of Official Statistics}, - volume = {25}, - year = {2009}, - number = {1}, - pages = {149--149} -} - -@article{webster2019, - title = {Decomposing multilateral price indexes into the contributions of individual commodities}, - author = {Webster, M. B. and Tarnow-Mordi, R. C.}, - journal = {Journal of Official Statistics}, - volume = {35}, - issue = {2}, - year = {2019}, - pages = {461--486}, - doi = {10.2478/jos-2019-0020} -} - -@techreport{martin2021, - title = {A note on generalized decompositions for price indexes}, - author = {Martin, S.}, - year = {2021}, - institution = {Statistics Canada} -} - -@techreport{vonderlippe2015, - title = {Generalized Statistical Means and New Price Index Formulas, Notes on some unexplored index formulas, their interpretations and generalizations}, - author = {{von der Lippe}, P.}, - year = {2015}, - institution = {Munich Personal RePEc Archive paper no. 64952} -} - -@book{vonderlippe2007, - title = {Index Theory and Price Statistics}, - author = {Peter von der Lippe}, - year = {2007}, - publisher = {Peter Lang}, - doi = {10.3726/978-3-653-01120-3} -} - -@article{fare2025, - title = {An alternative derivation of the van {IJ}zeren weights and some new results for the additive decomposition of {F}isher indices}, - author = {F{\"a}re, R. and Karagiannis, G.}, - journal = {Journal of Productivity Analysis}, - volume = {64}, - number = {3}, - pages = {363--377}, - year = {2025}, - doi = {10.1007/s11123-025-00774-2} -} - -@article{martin2026, - title={A Note on the Additive Decomposition of {GEKS} Indexes}, - author={Martin, Steve}, - journal={Journal of Official Statistics}, - pages={0282423X261451318}, - year={2026}, - doi = {10.1177/0282423X261451318} -} diff --git a/vignettes/spatial-price-index.qmd b/vignettes/spatial-price-index.Rmd similarity index 95% rename from vignettes/spatial-price-index.qmd rename to vignettes/spatial-price-index.Rmd index a6da9e33..4246eff2 100644 --- a/vignettes/spatial-price-index.qmd +++ b/vignettes/spatial-price-index.Rmd @@ -2,12 +2,8 @@ title: "Spatial price indexes" vignette: > %\VignetteIndexEntry{Spatial price indexes} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- It is possible to rework the functions in this package to make a spatial, rather diff --git a/vignettes/subperiods.qmd b/vignettes/subperiods.Rmd similarity index 96% rename from vignettes/subperiods.qmd rename to vignettes/subperiods.Rmd index 53ffb42d..c8dcbb61 100644 --- a/vignettes/subperiods.qmd +++ b/vignettes/subperiods.Rmd @@ -2,12 +2,8 @@ title: "Aggregating over subperiods" vignette: > %\VignetteIndexEntry{Aggregating over subperiods} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- With the exception of `vignette("spatial-price-index")`, all the examples so far diff --git a/vignettes/superlative-aggregation.qmd b/vignettes/superlative-aggregation.Rmd similarity index 97% rename from vignettes/superlative-aggregation.qmd rename to vignettes/superlative-aggregation.Rmd index 1438e9fd..44d85e2e 100644 --- a/vignettes/superlative-aggregation.qmd +++ b/vignettes/superlative-aggregation.Rmd @@ -2,12 +2,8 @@ title: "Superlative aggregation" vignette: > %\VignetteIndexEntry{Superlative aggregation} - %\VignetteEngine{quarto::html} + %\VignetteEngine{litedown::vignette} %\VignetteEncoding{UTF-8} -knitr: - opts_chunk: - collapse: true - comment: '#>' --- All of the examples so far have used a single set of weights to