Skip to content

Commit 19757c7

Browse files
committed
Fixed incorrect validation for contributions
1 parent ef08541 commit 19757c7

14 files changed

Lines changed: 140 additions & 118 deletions

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: piar
22
Title: Price Index Aggregation
3-
Version: 0.8.2.9004
3+
Version: 0.8.2.9005
44
Authors@R: c(
55
person("Steve", "Martin", role = c("aut", "cre", "cph"),
66
email = "marberts@protonmail.com",

R/aggregate.piar_index.R

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ aggregate_index <- function(
235235
)
236236
if (has_contrib) {
237237
res$contrib <- Map(
238-
super_aggregate_contrib(),
238+
super_aggregate_contrib(0),
239239
res$contrib,
240240
res2$contrib,
241241
res$index,
@@ -361,11 +361,10 @@ aggregate_contrib <- function(r, duplicate_contrib = c("make.unique", "sum")) {
361361
}
362362
}
363363

364-
365364
#' Aggregate product contributions for a superlative index
366365
#' @noRd
367-
super_aggregate_contrib <- function() {
368-
arithmetic_weights <- gpindex::transmute_weights(0, 1)
366+
super_aggregate_contrib <- function(r) {
367+
arithmetic_weights <- gpindex::transmute_weights(r, 1)
369368
Vectorize(
370369
function(x, y, rel1, rel2) {
371370
w <- arithmetic_weights(c(rel1, rel2))

R/contrib.R

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,8 @@ contrib.piar_index <- function(x,
9292
# replace with the actual values so products that didn't sell have 0 and
9393
# not NA contributions.
9494
out[] <- list(structure(rep.int(pad, length(products)), names = products))
95-
res <- Map(replace, out, con_names, con)
96-
res <- do.call(cbind, res)
97-
names(dimnames(res)) <- c("levels", "time")
95+
res <- do.call(cbind, Map(replace, out, con_names, con))
96+
names(dimnames(res)) <- c("product", "time")
9897
res
9998
}
10099

R/helpers.R

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ padded_extract <- function(x, i, pad) {
99
}
1010

1111
#---- Replacing contributions ----
12-
near <- function(x, y, tol = .Machine$double.eps^0.5) {
13-
abs(x - y) < tol
14-
}
15-
16-
valid_replacement_contrib <- function(index, contrib) {
12+
valid_replacement_contrib <- function(index,
13+
contrib,
14+
tol = .Machine$double.eps^0.5) {
1715
if (length(contrib) == 0L) {
18-
TRUE
19-
} else if (is.na(index)) {
20-
anyNA(contrib)
16+
return(TRUE)
17+
}
18+
valid <- sum(contrib, na.rm = TRUE) <= index - 1 + tol
19+
if (is.na(index)) {
20+
anyNA(contrib) || valid
2121
} else {
22-
near(sum(contrib, na.rm = TRUE), index - 1)
22+
valid
2323
}
2424
}
2525

R/mean.piar_index.R

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@
5050
#' A price index, averaged over subperiods, that inherits from the same
5151
#' class as `x`.
5252
#'
53-
#' @references Balk, B. M. (2008). *Price and Quantity Index Numbers*.
53+
#' @references
54+
#' Balk, B. M. (2008). *Price and Quantity Index Numbers*.
5455
#' Cambridge University Press.
5556
#'
5657
#' @examples
@@ -62,15 +63,14 @@
6263
#' @family index methods
6364
#' @export
6465
mean.chainable_piar_index <- function(
65-
x,
66-
...,
67-
weights = NULL,
68-
window = ntime(x),
69-
na.rm = FALSE,
70-
contrib = TRUE,
71-
r = 1,
72-
duplicate_contrib = c("make.unique", "sum")
73-
) {
66+
x,
67+
...,
68+
weights = NULL,
69+
window = ntime(x),
70+
na.rm = FALSE,
71+
contrib = TRUE,
72+
r = 1,
73+
duplicate_contrib = c("make.unique", "sum")) {
7474
chkDots(...)
7575
mean_index(
7676
x,
@@ -87,15 +87,14 @@ mean.chainable_piar_index <- function(
8787
#' @rdname mean.piar_index
8888
#' @export
8989
mean.direct_piar_index <- function(
90-
x,
91-
...,
92-
weights = NULL,
93-
window = ntime(x),
94-
na.rm = FALSE,
95-
contrib = TRUE,
96-
r = 1,
97-
duplicate_contrib = c("make.unique", "sum")
98-
) {
90+
x,
91+
...,
92+
weights = NULL,
93+
window = ntime(x),
94+
na.rm = FALSE,
95+
contrib = TRUE,
96+
r = 1,
97+
duplicate_contrib = c("make.unique", "sum")) {
9998
chkDots(...)
10099
mean_index(
101100
x,
@@ -112,15 +111,14 @@ mean.direct_piar_index <- function(
112111
#' Internal function to aggregate over subperiods
113112
#' @noRd
114113
mean_index <- function(
115-
x,
116-
weights,
117-
window,
118-
na.rm,
119-
contrib,
120-
r,
121-
chainable,
122-
duplicate_contrib
123-
) {
114+
x,
115+
weights,
116+
window,
117+
na.rm,
118+
contrib,
119+
r,
120+
chainable,
121+
duplicate_contrib) {
124122
if (!is.null(weights)) {
125123
weights <- as.numeric(weights)
126124
if (length(weights) != length(x$time) * length(x$levels)) {

tests/Examples/piar-Ex.Rout.save

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -404,12 +404,12 @@ levels 1 2 3
404404
> # Percent-change contributions for the top-level index
405405
>
406406
> contrib(index)
407-
time
408-
levels 1 2
409-
a.1 0.0000000 0.5081686
410-
a.2 0.2440169 0.6442213
411-
b.1 0.3905243 2.0513858
412-
b.2 0.8284271 2.4871732
407+
time
408+
product 1 2
409+
a.1 0.0000000 0.5081686
410+
a.2 0.2440169 0.6442213
411+
b.1 0.3905243 2.0513858
412+
b.2 0.8284271 2.4871732
413413
>
414414
> contrib2DF(index)
415415
period level product value

tests/test-making-price-indexes.Rout.save

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -361,28 +361,28 @@ levels 202001 202002 202003 202004
361361
>
362362
> ## -----------------------------------------------------------------------------
363363
> contrib(ms_elemental)
364-
time
365-
levels 202001 202002 202003 202004
366-
1 0 0.0000000 0.0000000 0
367-
2 NA NA -0.6657061 0
368-
3 0 -0.1050903 NA NA
364+
time
365+
product 202001 202002 202003 202004
366+
1 0 0.0000000 0.0000000 0
367+
2 NA NA -0.6657061 0
368+
3 0 -0.1050903 NA NA
369369
>
370370
> ## -----------------------------------------------------------------------------
371371
> contrib(aggregate(ms_elemental, pias, na.rm = TRUE))
372-
time
373-
levels 202001 202002 202003 202004
374-
1 0 0.00000000 0.0000000 0.000000000
375-
10 0 -0.08782076 0.2731949 -0.078173579
376-
11 0 0.00000000 NA 0.059392635
377-
12 0 0.00000000 NA 1.322915301
378-
2 NA NA -0.2928098 0.000000000
379-
3 0 -0.06718490 NA NA
380-
4 0 NA NA -0.018209690
381-
5 0 NA NA 0.094562963
382-
6 0 NA NA 0.427935081
383-
7 0 0.51646606 -0.2054665 -0.011177530
384-
8 0 0.01906845 0.1755868 -0.003784845
385-
9 0 -0.07980493 0.1125689 -0.058699008
372+
time
373+
product 202001 202002 202003 202004
374+
1 0 0.00000000 0.0000000 0.000000000
375+
10 0 -0.08782076 0.2731949 -0.078173579
376+
11 0 0.00000000 NA 0.059392635
377+
12 0 0.00000000 NA 1.322915301
378+
2 NA NA -0.2928098 0.000000000
379+
3 0 -0.06718490 NA NA
380+
4 0 NA NA -0.018209690
381+
5 0 NA NA 0.094562963
382+
6 0 NA NA 0.427935081
383+
7 0 0.51646606 -0.2054665 -0.011177530
384+
8 0 0.01906845 0.1755868 -0.003784845
385+
9 0 -0.07980493 0.1125689 -0.058699008
386386
>
387387
> ## -----------------------------------------------------------------------------
388388
> ms_prices1 <- subset(ms_prices, period <= "202003")
@@ -677,20 +677,20 @@ levels 202001 202002 202003 202004
677677
+ w[2, col(paasche_contrib)] * paasche_contrib
678678
>
679679
> fisher_contrib
680-
time
681-
levels 202001 202002 202003 202004
682-
1 0 0.00000000 0.00000000 0.000000000
683-
10 0 -0.13327742 0.17296129 -0.131946938
684-
11 0 0.00000000 NA 0.039533034
685-
12 0 0.00000000 NA 0.880561300
686-
2 NA NA -0.42962331 0.000000000
687-
3 0 -0.04756479 NA NA
688-
4 0 NA NA -0.012019870
689-
5 0 NA NA 0.062419211
690-
6 0 NA NA 0.282471798
691-
7 0 0.78379264 -0.13008203 -0.018866231
692-
8 0 0.02893842 0.11116498 -0.006388331
693-
9 0 -0.12111255 0.07126804 -0.099076370
680+
time
681+
product 202001 202002 202003 202004
682+
1 0 0.00000000 0.00000000 0.000000000
683+
10 0 -0.13327742 0.17296129 -0.131946938
684+
11 0 0.00000000 NA 0.039533034
685+
12 0 0.00000000 NA 0.880561300
686+
2 NA NA -0.42962331 0.000000000
687+
3 0 -0.04756479 NA NA
688+
4 0 NA NA -0.012019870
689+
5 0 NA NA 0.062419211
690+
6 0 NA NA 0.282471798
691+
7 0 0.78379264 -0.13008203 -0.018866231
692+
8 0 0.02893842 0.11116498 -0.006388331
693+
9 0 -0.12111255 0.07126804 -0.099076370
694694
>
695695
> ## -----------------------------------------------------------------------------
696696
> chain(fisher)

tests/testthat/test-aggregate.R

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,13 @@ test_that("partial contributions are correct", {
387387
})
388388

389389
test_that("duplicate products get unique names during aggregation", {
390-
epr1 <- elemental_index(setNames(1:4, 1:4), ea = gl(2, 2), period = gl(1, 4), contrib = TRUE, r = 1)
390+
epr1 <- elemental_index(
391+
setNames(1:4, 1:4),
392+
ea = gl(2, 2),
393+
period = gl(1, 4),
394+
contrib = TRUE,
395+
r = 1
396+
)
391397
epr2 <- epr1
392398
levels(epr2) <- 3:4
393399
index <- aggregate(
@@ -396,7 +402,7 @@ test_that("duplicate products get unique names during aggregation", {
396402
)
397403
expect_equal(
398404
contrib(index, "a"),
399-
matrix(c(0, 0.25, 0.5, 0.75), 4, dimnames = list(levels = 1:4, time = 1))
405+
matrix(c(0, 0.25, 0.5, 0.75), 4, dimnames = list(product = 1:4, time = 1))
400406
)
401407
expect_equal(
402408
contrib(index, "a"),
@@ -406,7 +412,7 @@ test_that("duplicate products get unique names during aggregation", {
406412
contrib(index),
407413
matrix(rep(c(0, 0.125, 0.25, 0.375), each = 2), 8,
408414
dimnames = list(
409-
levels = c(1, "1.1", 2, "2.1", 3, "3.1", 4, "4.1"),
415+
product = c(1, "1.1", 2, "2.1", 3, "3.1", 4, "4.1"),
410416
time = 1
411417
)
412418
)
@@ -631,3 +637,18 @@ test_that("superlative index aggregates correctly", {
631637
aggregate(epr, pias, pias2 = pias, r = 0, na.rm = TRUE)
632638
)
633639
})
640+
641+
test_that("duplicate product methods work with NAs", {
642+
x <- as_index(c(1, 2, NA))
643+
contrib(x, 1) <- c(0.5, -0.25, NA, -0.25)
644+
contrib(x, 3) <- c(1, NA, NA)
645+
pias <- list(c(0, 0, 0), 1:3)
646+
expect_equal(
647+
contrib(aggregate(x, pias, duplicate_contrib = "sum")),
648+
matrix(c(0.25, -0.125, NA, -0.125), dimnames = list(product = 1:4, time = 1))
649+
)
650+
expect_equal(
651+
contrib(aggregate(x, pias, duplicate_contrib = "sum", na.rm = TRUE)),
652+
matrix(c(0.25, -0.125, NA, -0.125), dimnames = list(product = 1:4, time = 1))
653+
)
654+
})

tests/testthat/test-as_index.R

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
dat <- data.frame(rel = c(1:6, NA, 7, 8),
2-
period = c(1, 1, 1, 1, 1, 2, 2, 2, 2),
3-
ea = c("11", "11", "12", "12", "13", "11", "12", "11", "14"))
1+
dat <- data.frame(
2+
rel = c(1:6, NA, 7, 8),
3+
period = c(1, 1, 1, 1, 1, 2, 2, 2, 2),
4+
ea = c("11", "11", "12", "12", "13", "11", "12", "11", "14")
5+
)
46

57
pias <- as_aggregation_structure(
68
data.frame(level1 = 1, level2 = c(11, 12, 13, 14), weight = 1)
@@ -24,9 +26,10 @@ test_that("as_index works with matrices", {
2426
expect_equal(as_index(as.matrix(epr)), epr2)
2527
expect_equal(
2628
contrib(as_index(as.matrix(epr), contrib = TRUE)),
27-
as.matrix(epr)[1, , drop = FALSE] - 1
29+
as.matrix(epr)[1, , drop = FALSE] - 1,
30+
ignore_attr = TRUE
2831
)
29-
32+
3033
# A character vector used to get pass through without coercion.
3134
mat <- as.matrix(epr)
3235
mat[] <- as.character(mat)
@@ -38,7 +41,8 @@ test_that("as_index works for data frames", {
3841
expect_equal(as_index(as.data.frame(epr)), epr2)
3942
expect_equal(
4043
contrib(as_index(as.data.frame(epr), contrib = TRUE)),
41-
as.matrix(epr)[1, , drop = FALSE] - 1
44+
as.matrix(epr)[1, , drop = FALSE] - 1,
45+
ignore_attr = TRUE
4246
)
4347
df <- as.data.frame(epr)
4448
df[[1]] <- factor(df[[1]], levels = 2:1)
@@ -49,12 +53,12 @@ test_that("as_index works for data frames", {
4953
elemental_index(rel, period = factor(period, levels = 2:1), ea = ea)
5054
)
5155
)
52-
56+
5357
expect_equal(
5458
as_index(data.frame(1:5, 1:5, 1:5)),
5559
as_index(matrix(replace(NA, c(1, 7, 13, 19, 25), 1:5), 5))
5660
)
57-
61+
5862
expect_error(as_index(df[1:2]))
5963
})
6064

@@ -74,17 +78,17 @@ test_that("as_index works with contribs", {
7478
as_index(as.data.frame(epr2, contrib = TRUE), contrib = TRUE),
7579
epr2
7680
)
77-
81+
7882
index2 <- aggregate(epr, pias, contrib = FALSE)
7983
index2df <- as.data.frame(index2, contrib = TRUE)
8084
expect_equal(
8185
as_index(index2df[-1, ], contrib = TRUE),
8286
index2
8387
)
84-
88+
8589
index2df[1, 4] <- list(a = 0)
8690
expect_error(as_index(index2df, contrib = TRUE))
87-
91+
8892
index2df[1, 4][[1]] <- list(c(a = 2, a = 1, b = NA))
8993
expect_warning(index2 <- as_index(index2df, contrib = TRUE))
9094
expect_identical(rownames(contrib(index2)), c("a", "a.1", "b"))

0 commit comments

Comments
 (0)