From b2daaec850d3579d363aec3f197addfb121c71a0 Mon Sep 17 00:00:00 2001 From: Tim Bock Date: Sun, 8 Aug 2021 17:25:40 +1000 Subject: [PATCH 1/8] DS-3465 Tweaks to existing function 1. Dealing with no subset 2. Adding decimals to print statement 3. Fixing some typos --- R/calibrate.R | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/R/calibrate.R b/R/calibrate.R index e0dd281..45d5fee 100755 --- a/R/calibrate.R +++ b/R/calibrate.R @@ -8,9 +8,9 @@ #' @param lower A lower bound weight value (not guaranteed to be achieved). #' @param upper An upper bound weight value (not guaranteed to be achieved). #' @param trim.iterations The number of times to run the trim loop over the final weightings -#' @param always.calibrate If \code{FALSE}, whcih is the default, +#' @param always.calibrate If \code{FALSE}, which is the default, #' problems with only categorical adjustment variables are solved via -#' iterative-proprtional fitting (raking). Otherwise, they are solved via calibration. +#' iterative-proportional fitting (raking). Otherwise, they are solved via calibration. #' @param package The R package used to calibrate the model when raking is not conducted. #' Defaults to \code{CVXR} (see https://cvxr.rbind.io/cvxr_examples/cvxr_survey_calibration/). Other options #' are \code{icarus} and \code{survey}. . @@ -124,6 +124,8 @@ convertToDataFrame <- function(x) categoricalTargets <- function(adjustment.variables, categorical.targets, subset) { targets = list() + if (missing(subset)) + subset <- rep(TRUE, nrow(adjustment.variables)) n.categorical = length(adjustment.variables) if (n.categorical != length(categorical.targets)) { stop("The number of categorical adjustment variables needs to be the same as the number of sets of targets (it isn't)") @@ -175,6 +177,8 @@ numericTargets <- function(targets, adjustment.variables, numeric.targets, subse { n.categorical = length(targets) n = NROW(adjustment.variables) + if (missing(subset)) + subset <- rep(TRUE, n) if (length(adjustment.variables) - n.categorical != length(numeric.targets)) { stop("The number of numeric adjustment variables needs to be the same as the number of sets of targets (it isn't)") @@ -358,7 +362,7 @@ print.Calibrate <- function (x, ...) if (!is.null(product)) instruction.for.getting.variable <- "\n\nTo save the variable, click SAVE VARIABLE(S) > Save Weight Variable from Configuration" ess = EffectiveSampleSize(x) - ess.percent = round(ess / length(x) * 100) + ess.percent = round(ess / length(x) * 100, 1) n = length(x) rng = range(x) @@ -368,6 +372,6 @@ print.Calibrate <- function (x, ...) FormatAsReal(ess, decimals = 0), " (", ess.percent, "%)\n", "Smallest weight is ", FormatAsReal(rng[1], decimals = 3), "\n", - "Largest weight is ", FormatAsReal(rng[2], decimals = 3), " (", FormatAsReal(rng[2] / rng[1], decimals = 1), " times the smallest weight)", + "Largest weight is ", FormatAsReal(rng[2], decimals = 3), " (", FormatAsReal(rng[2] / rng[1], decimals = 3), " times the smallest weight)", instruction.for.getting.variable)) } From 9a01ef82d42f19141805fec3e0f6f4684c7900e3 Mon Sep 17 00:00:00 2001 From: Tim Bock Date: Sun, 8 Aug 2021 18:16:24 +1000 Subject: [PATCH 2/8] DS-3465 Updating documentation --- man/Calibrate.Rd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/Calibrate.Rd b/man/Calibrate.Rd index 1c24421..ded6420 100755 --- a/man/Calibrate.Rd +++ b/man/Calibrate.Rd @@ -38,9 +38,9 @@ Defaults to \code{CVXR} (see https://cvxr.rbind.io/cvxr_examples/cvxr_survey_cal are \code{icarus} and \code{survey}. . Use icarus with care, as sometimes target categories can be switched around} -\item{always.calibrate}{If \code{FALSE}, whcih is the default, +\item{always.calibrate}{If \code{FALSE}, which is the default, problems with only categorical adjustment variables are solved via -iterative-proprtional fitting (raking). Otherwise, they are solved via calibration.} +iterative-proportional fitting (raking). Otherwise, they are solved via calibration.} \item{subset}{A logical vector indicating which subset of cases should be used to create the weight} From af5463b6f3527fae1811bb242a355df702183aff Mon Sep 17 00:00:00 2001 From: Tim Bock Date: Mon, 9 Aug 2021 07:52:08 +1000 Subject: [PATCH 3/8] DS-3465 Basic functionality works The basic functionality is as it is needed: numeric variables work, as do constraints. --- NAMESPACE | 1 + R/weightingdialog.R | 117 +++++++++++++++++++++++ man/WeightingDialog.Rd | 41 ++++++++ tests/testthat/test-weightingdialog.R | 132 ++++++++++++++++++++++++++ 4 files changed, 291 insertions(+) create mode 100644 R/weightingdialog.R create mode 100644 man/WeightingDialog.Rd create mode 100644 tests/testthat/test-weightingdialog.R diff --git a/NAMESPACE b/NAMESPACE index 8686def..6e54105 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -44,6 +44,7 @@ export(SplitFormQuestions) export(StackData) export(TidyRawData) export(WeightedSurveyDesign) +export(WeightingDialog) importFrom(CVXR,Minimize) importFrom(CVXR,Problem) importFrom(CVXR,Variable) diff --git a/R/weightingdialog.R b/R/weightingdialog.R new file mode 100644 index 0000000..871fe4e --- /dev/null +++ b/R/weightingdialog.R @@ -0,0 +1,117 @@ +#' \code{WeightsDialog} +#' @description Code for the Displayr Weighting dialog box. +#' @param categorical.variables An optional list or data frame of categorical adjustment variables. +#' @param categorical.targets The target probabilities for each category listed in \code{categorical.variables} +#' @param numeric.variables An optional list or data frame of categorical adjustment variables. +#' @param numeric.targets the target mean for each numeric variable in numeric.variables +#' @param lower A lower bound weight value (not guaranteed to be achieved). +#' @param upper An upper bound weight value (not guaranteed to be achieved). +#' @param calfun The calibration function: Raking (Default), Linear, Quadratic. +#' @param input.weight An optional weight variable; if supplied, the created weight is created to be as close +#' to this input.weight as possible +#' @return numeric A vector of weights +#' @importFrom icarus calibration +#' @export + + +WeightingDialog <- function(categorical.variables = NULL, + categorical.targets = NULL, + numeric.variables = NULL, + numeric.targets = NULL, + lower = "", + upper = "", + calfun = c("Raking", "Linear", "Logit")[1], + input.weight = NULL) +{ + + # Preparing inputs + adjustment.variables = NULL + calfun = tolower(calfun) + targets = list() + + if ((is.null(categorical.variables) || length(categorical.variables) == 0) && (is.null(numeric.variables) || length(numeric.variables) == 0)) { + stop("Nothing to do! At least one categorical OR numeric variable required.") + } + + # Categorical inputs + if (!is.null(categorical.variables)) + { + adjustment.variables = convertToDataFrame(categorical.variables) + categorical.targets = if (is.null(categorical.targets) || is.list(categorical.targets)) categorical.targets else list(categorical.targets) + targets = categoricalTargets(adjustment.variables, categorical.targets) + } + n.categorical = length(targets) + + # Numeric inputs + has.numerics <- !is.null(numeric.variables) + if (has.numerics) + { + num.adjustment.variables = convertToDataFrame(numeric.variables) + adjustment.variables = if (is.null(categorical.variables)) num.adjustment.variables else cbind(adjustment.variables, num.adjustment.variables) + targets = numericTargets(targets, adjustment.variables, numeric.targets) + } + + # Adding input.weight or a proxy (and normalizing to a mean of 1) + n = NROW(adjustment.variables) + weight = if (is.null(input.weight)) rep(1, n) else input.weight / mean(input.weight) + + # Removing empty factor levels + if (n.categorical > 0) + for (i in 1:n.categorical) # ordered = FALSE needed for weirdness in survey package + adjustment.variables[[i]] = factor(adjustment.variables[[i]], ordered = FALSE) + + # Creating the table of margins/targets in the desired format + marg = createMargins(targets, adjustment.variables, n.categorical, FALSE, "survey") + # Calculating/updating the weight + wgt = computeWeightsDialog(adjustment.variables, has.numerics, marg, weight, lower, upper, calfun) + wgt / mean(wgt) + class(wgt) <- "Calibrate" + wgt +} + + + +# Calibration function +#' @importFrom survey calibrate rake +#' @importFrom stats model.matrix weights terms.formula +#' @importFrom CVXR Variable Minimize Problem entr solve +#' @importFrom verbs Sum +computeWeightsDialog <- function(adjustment.variables, has.numerics, margins, input.weight, lower, upper, calfun) +{ + if (lower == "" & upper == "" & !has.numerics) + stop("This should be processed via the existing Q algorithm and this code should not have been called.") + # Bounds + if (lower == "") + lower = 0 + if (upper == "") + upper = Inf + if (calfun == "logit") + { + upper = min(1000, upper)# Avoiding having a denominator if Inf in Phi_R + # We are using CVXR to do logit just in case survey package doesn't scale well, so there is a fallback + # That is, we could have done it all in survey, but + formula = createFormula(adjustment.variables) + # wrapping formula with terms.formula fixes the + # "argument "frml" is missing, with no default" + # bug on the R server + X <- model.matrix(object = terms.formula(formula), + data = adjustment.variables) + A <- input.weight * X + n <- NROW(X) + g <- Variable(n) + constraints = list(t(A) %*% g == margins) + Phi_R = Minimize(sum(input.weight * (-entr((g - lower) / (upper - lower)) - (entr((upper - g) / (upper - lower)))))) + p = Problem(Phi_R, constraints) + res = solve(p) + as.numeric(input.weight * res$getValue(g)) + } else { + weights(calibrate(svydesign(ids = ~1, weights = ~input.weight, data = adjustment.variables), + createFormula(adjustment.variables), + maxit = 1000, + epsilon = 1e-8, + bounds = c(lower, upper), + population = margins, + calfun = calfun)) + } +} + diff --git a/man/WeightingDialog.Rd b/man/WeightingDialog.Rd new file mode 100644 index 0000000..27b350c --- /dev/null +++ b/man/WeightingDialog.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/weightingdialog.R +\name{WeightingDialog} +\alias{WeightingDialog} +\title{\code{WeightsDialog}} +\usage{ +WeightingDialog( + categorical.variables = NULL, + categorical.targets = NULL, + numeric.variables = NULL, + numeric.targets = NULL, + lower = "", + upper = "", + calfun = c("Raking", "Linear", "Logit")[1], + input.weight = NULL +) +} +\arguments{ +\item{categorical.variables}{An optional list or data frame of categorical adjustment variables.} + +\item{categorical.targets}{The target probabilities for each category listed in \code{categorical.variables}} + +\item{numeric.variables}{An optional list or data frame of categorical adjustment variables.} + +\item{numeric.targets}{the target mean for each numeric variable in numeric.variables} + +\item{lower}{A lower bound weight value (not guaranteed to be achieved).} + +\item{upper}{An upper bound weight value (not guaranteed to be achieved).} + +\item{calfun}{The calibration function: Raking (Default), Linear, Quadratic.} + +\item{input.weight}{An optional weight variable; if supplied, the created weight is created to be as close +to this input.weight as possible} +} +\value{ +numeric A vector of weights +} +\description{ +Code for the Displayr Weighting dialog box. +} diff --git a/tests/testthat/test-weightingdialog.R b/tests/testthat/test-weightingdialog.R new file mode 100644 index 0000000..c5db85b --- /dev/null +++ b/tests/testthat/test-weightingdialog.R @@ -0,0 +1,132 @@ +library(testthat) + +context("Tests for the R Code Weights Dialog in Displayr") + +weighted.table = function(weight, variable) { prop.table(tapply(weight, variable, sum)) } + +marriage = foreign::read.spss("https://docs.displayr.com/images/8/89/Marriage.sav", to.data.frame = TRUE) + +input.weight = marriage$weight + +input.age = marriage$age.cat +input.gender = marriage$female +input.race = marriage$race.wbh +input.race.white = as.integer(input.race == "White") +input.race.black = as.integer(input.race == "Black") +input.race.hispanic = as.integer(input.race == "Hispanic") +marriage$region.cat = as.character(marriage$region.cat) +marriage$region.cat[marriage$region.cat %in% c("DC", "Northeast")] = "Northeast + DC" +marriage$region.cat = factor(marriage$region.cat) +input.region = marriage$region.cat + +variable.targets.age = structure(c("18-29", "30-44", "45-64", "65+", ".4", ".3", ".2", ".1"), .Dim = c(4L, 2L)) +variable.targets.race = structure(c(0.8, 0.1, 0.1)) +variable.targets.age2 = structure(c("18-29", "30-44", "45-64", "65+", ".2", ".3",".31", ".19"), .Dim = c(4L, 2L)) +variable.targets.gender = structure(c("Male", "Female", "0.45", "0.55"), .Dim=c(2L, 2L)) +variable.targets.region = structure(c("Midwest", "Northeast + DC", "South", "West", ".27", "0.26", "0.24", "0.23"), .Dim=c(4L, 2L)) + +test_that("Multiple Categorical inputs", { + + expect_error(WeightingDialog(categorical.variables = data.frame(input.age, input.gender, input.region), + categorical.targets=list(variable.targets.age2, variable.targets.gender, variable.targets.region)), + "This should be processed via the existing Q algorithm and this code should not have been called.") + +}) + +# Comparing all algorithms with a single categorical adjustment variable +test_that("Single Categorical adjustment variable", { + + # Raking with no bounds and no numeric + expect_error(WeightingDialog(list(Age = input.age), variable.targets.age), + "This should be processed via the existing Q algorithm and this code should not have been called.") + + # Raking with trvial lower and upper values + wgt.calibrate = Calibrate(list(Age = input.age), variable.targets.age, package = "icarus", always.calibrate = TRUE) + wgt.dialog = WeightingDialog(list(Age = input.age), variable.targets.age, lower = 0, upper = 1000) + expect_equivalent(cor(wgt.calibrate, wgt.dialog), 1) + + # linear + wgt.dialog = WeightingDialog(list(Age = input.age), variable.targets.age, lower = 0, upper = 1000, calfun = "linear") + expect_equivalent(cor(wgt.calibrate, wgt.dialog), 1) + + # logit + wgt.dialog = WeightingDialog(list(Age = input.age), variable.targets.age, lower = 0, upper = 1000, calfun = "logit") + expect_equivalent(cor(wgt.calibrate, wgt.dialog), 1) +}) + + +for (calfun in c("Raking", "Linear", "Logit")){ + + test_that("Numeric input", { + numeric.variables = list(input.race.white, input.race.black, input.race.hispanic) + wgt = WeightingDialog(numeric.variables = numeric.variables, + numeric.targets = variable.targets.race, + calfun = calfun) + actual.weighted.means <- weighted.table(wgt, input.race) + expect_equivalent(actual.weighted.means, variable.targets.race) + }) + + test_that("Categorical and Numeric input", { + wgt = WeightingDialog( + categorical.variables=input.age, + categorical.targets=variable.targets.age, + numeric.variables = data.frame(input.race.white, input.race.black, input.race.hispanic), + numeric.targets=variable.targets.race, calfun = calfun + ) + + actual.weighted.means <- tapply(wgt, input.race, sum) / length(input.race) + expect_equivalent(actual.weighted.means, variable.targets.race, tol = 0.0000001) + + actual.weighted.means <- tapply(wgt, input.age, sum) / length(input.age) + expect_equivalent(actual.weighted.means, as.numeric(variable.targets.age[5:8]), tol = 0.0000001) +}) + +} + + +test_that("Calmar examples: http://vesselinov.com/CalmarEngDoc.pdf", + { # Note that we compare the resulting statisics, but not the weights themselves + # as there are an infinite number of possible weights. + # 1 numeric + x = c(1,1,1,2,2,4,6,7,8,11,12,10,15,20,50) + #variable.targets.age = structure(c("18-29", "30-44", "45-64", "65+", ".4", ".3", ".2", ".1"), .Dim = c(4L, 2L)) + target.x = mean(x) * 1400 / 1200 + for (calfun in c("Raking", "Linear", "Logit")) + { + wgt = WeightingDialog(numeric.variables = data.frame(x), + numeric.targets = target.x, calfun = calfun) + expect_equal(sum(x * wgt) * 8, 1400 , tol = 0.1) + } + for (calfun in c("Raking", "Linear", "Logit")) + { + wgt = WeightingDialog(numeric.variables = data.frame(x), + numeric.targets = target.x, calfun = calfun, + lower = 0.9) + expect_equal(sum(x * wgt) * 8, 1400, tol = 0.1) + } + + # 1 numeric and 1 categorical + y = factor(c("a","a","b","b","c","a","c","c","b","a","a","b","c","c","b")) + for (calfun in c("Raking", "Linear", "Logit")) + { + wgt = WeightingDialog(data.frame(y), + structure(c("a", "b", "c", prop.table(c(38, 41, 39))), .Dim = c(3L, 2L)), numeric.variables = data.frame(x), + numeric.targets = target.x, calfun = calfun) + expect_equal(sum(x * wgt) * 8, 1400, tol = 0.1) + expect_equal(sum(prop.table(wgt)[y == "a"]), 38/118, tol = 0.0001) + expect_equal(sum(prop.table(wgt)[y == "b"]), 41/118, tol = 0.0001) + expect_equal(sum(prop.table(wgt)[y == "c"]), 39/118, tol = 0.0001) + } + for (calfun in c("Raking", "Linear", "Logit")) + { + wgt = WeightingDialog(data.frame(y), + structure(c("a", "b", "c", prop.table(c(38, 41, 39))), .Dim = c(3L, 2L)), numeric.variables = data.frame(x), + numeric.targets = target.x, calfun = calfun) + expect_equal(sum(x * wgt) * 8, 1400 , tol = 0.1) + expect_equal(sum(prop.table(wgt)[y == "a"]), 38/118, tol = 0.0001, lower = 0.9) + expect_equal(sum(prop.table(wgt)[y == "b"]), 41/118, tol = 0.0001, lower = 0.9) + expect_equal(sum(prop.table(wgt)[y == "c"]), 39/118, tol = 0.0001, lower = 0.9) + } + }) + + From ba1e587fccb8f7e4dead56c6470be5034bf6efd0 Mon Sep 17 00:00:00 2001 From: Tim Bock Date: Mon, 9 Aug 2021 09:23:00 +1000 Subject: [PATCH 4/8] DS-3465 Grossing --- R/weightingdialog.R | 19 ++++-- tests/testthat/test-weightingdialog.R | 94 +++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/R/weightingdialog.R b/R/weightingdialog.R index 871fe4e..30fe67a 100644 --- a/R/weightingdialog.R +++ b/R/weightingdialog.R @@ -9,8 +9,9 @@ #' @param calfun The calibration function: Raking (Default), Linear, Quadratic. #' @param input.weight An optional weight variable; if supplied, the created weight is created to be as close #' to this input.weight as possible +#' @param force.to.n Force the sum of weights to equal the sample size. +#' #' @return numeric A vector of weights -#' @importFrom icarus calibration #' @export @@ -21,6 +22,7 @@ WeightingDialog <- function(categorical.variables = NULL, lower = "", upper = "", calfun = c("Raking", "Linear", "Logit")[1], + force.to.n = TRUE, input.weight = NULL) { @@ -34,13 +36,20 @@ WeightingDialog <- function(categorical.variables = NULL, } # Categorical inputs - if (!is.null(categorical.variables)) + n.categorical = if(is.null(categorical.variables)) 0 else NCOL(categorical.variables) + if (n.categorical > 0 ) { adjustment.variables = convertToDataFrame(categorical.variables) categorical.targets = if (is.null(categorical.targets) || is.list(categorical.targets)) categorical.targets else list(categorical.targets) + gross <- rep(NA, n.categorical) + for (i in 1:n.categorical) + { + nm <- as.numeric(categorical.targets[[i]][, 2]) + gross[i] <- sum(nm) + categorical.targets[[i]][,2] <- prop.table(nm) + } targets = categoricalTargets(adjustment.variables, categorical.targets) } - n.categorical = length(targets) # Numeric inputs has.numerics <- !is.null(numeric.variables) @@ -51,7 +60,7 @@ WeightingDialog <- function(categorical.variables = NULL, targets = numericTargets(targets, adjustment.variables, numeric.targets) } - # Adding input.weight or a proxy (and normalizing to a mean of 1) + # Adding input.weight or a proxy (and normalizing to a mean of Total / n) n = NROW(adjustment.variables) weight = if (is.null(input.weight)) rep(1, n) else input.weight / mean(input.weight) @@ -65,6 +74,8 @@ WeightingDialog <- function(categorical.variables = NULL, # Calculating/updating the weight wgt = computeWeightsDialog(adjustment.variables, has.numerics, marg, weight, lower, upper, calfun) wgt / mean(wgt) + if (!force.to.n) + wgt <- wgt * gross[[1]] / n class(wgt) <- "Calibrate" wgt } diff --git a/tests/testthat/test-weightingdialog.R b/tests/testthat/test-weightingdialog.R index c5db85b..c29f6be 100644 --- a/tests/testthat/test-weightingdialog.R +++ b/tests/testthat/test-weightingdialog.R @@ -97,6 +97,7 @@ test_that("Calmar examples: http://vesselinov.com/CalmarEngDoc.pdf", numeric.targets = target.x, calfun = calfun) expect_equal(sum(x * wgt) * 8, 1400 , tol = 0.1) } + # Adding a constraint for (calfun in c("Raking", "Linear", "Logit")) { wgt = WeightingDialog(numeric.variables = data.frame(x), @@ -130,3 +131,96 @@ test_that("Calmar examples: http://vesselinov.com/CalmarEngDoc.pdf", }) +test_that("Totals for a categorical adjustment variable", + { + x = c(1,1,1,2,2,4,6,7,8,11,12,10,15,20,50) + y = factor(c("a","a","b","b","c","a","c","c","b","a","a","b","c","c","b")) + target.x = mean(x) * 1400 / 1200 + for (calfun in c("Raking", "Linear", "Logit")) + { + wgt = WeightingDialog(data.frame(y), + structure(c("a", "b", "c", c(38, 41, 39)), .Dim = c(3L, 2L)), numeric.variables = data.frame(x), + numeric.targets = target.x, calfun = calfun) + expect_equal(sum(x * wgt) * 8, 1400 , tol = 0.1) + expect_equal(sum(prop.table(wgt)[y == "a"]), 38/118, tol = 0.0001, lower = 0.9) + expect_equal(sum(prop.table(wgt)[y == "b"]), 41/118, tol = 0.0001, lower = 0.9) + expect_equal(sum(prop.table(wgt)[y == "c"]), 39/118, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt), length(x)) + } + }) + +test_that("Grossing + Totals for a categorical adjustment variable", + { + x = c(1,1,1,2,2,4,6,7,8,11,12,10,15,20,50) + y = factor(c("a","a","b","b","c","a","c","c","b","a","a","b","c","c","b")) + target.x = mean(x) * 1400 / 1200 + for (calfun in c("Raking", "Linear", "Logit")) + { + wgt = WeightingDialog(data.frame(y), + structure(c("a", "b", "c", c(38, 41, 39)), .Dim = c(3L, 2L)), numeric.variables = data.frame(x), + numeric.targets = target.x, + calfun = calfun, + force.to.n = FALSE) + expect_equal(sum(x * wgt), 1400 , tol = 0.1) + expect_equal(sum(wgt[y == "a"]), 38, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt[y == "b"]), 41, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt[y == "c"]), 39, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt), 118) + } + }) + + +test_that("Grossing + Totals for two categorical adjustment variables", + { + x = c(1,1,1,2,2,4,6,7,8,11,12,10,15,20,50) + y = factor(c("a","a","b","b","c","a","c","c","b","a","a","b","c","c","b")) + target.x = mean(x) * 1400 / 1200 + # The same variable in twice + for (calfun in c("Raking", "Linear", "Logit")) + { + wgt = WeightingDialog(data.frame(y1 = y, y2 = y), + list(structure(c("a", "b", "c", c(38, 41, 39)), .Dim = c(3L, 2L)), + structure(c("a", "b", "c", c(38, 41, 39)), .Dim = c(3L, 2L))), + numeric.variables = data.frame(x), + numeric.targets = target.x, + calfun = calfun, + force.to.n = FALSE) + expect_equal(sum(x * wgt), 1400 , tol = 0.1) + expect_equal(sum(wgt[y == "a"]), 38, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt[y == "b"]), 41, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt[y == "c"]), 39, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt), 118) + } + # The same variable in twice - counts first, then percent + for (calfun in c("Raking", "Linear", "Logit")) + { + wgt = WeightingDialog(data.frame(y1 = y, y2 = y), + list(structure(c("a", "b", "c", c(38, 41, 39)), .Dim = c(3L, 2L)), + structure(c("a", "b", "c", prop.table(c(38, 41, 39))), .Dim = c(3L, 2L))), + numeric.variables = data.frame(x), + numeric.targets = target.x, + calfun = calfun, + force.to.n = FALSE) + expect_equal(sum(x * wgt), 1400 , tol = 0.1) + expect_equal(sum(wgt[y == "a"]), 38, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt[y == "b"]), 41, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt[y == "c"]), 39, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt), 118) + } + # The same variable in twice - percent first, then count + for (calfun in c("Raking", "Linear", "Logit")) + { + wgt = WeightingDialog(data.frame(y1 = y, y2 = y), + list(structure(c("a", "b", "c", prop.table(c(38, 41, 39))), .Dim = c(3L, 2L)), + structure(c("a", "b", "c", c(38, 41, 39)), .Dim = c(3L, 2L))), + numeric.variables = data.frame(x), + numeric.targets = target.x, + calfun = calfun, + force.to.n = FALSE) + expect_equal(sum(x * wgt) , 11.6667 , tol = 0.1) + expect_equal(sum(prop.table(wgt)[y == "a"]), 38/118, tol = 0.0001, lower = 0.9) + expect_equal(sum(prop.table(wgt)[y == "b"]), 41/118, tol = 0.0001, lower = 0.9) + expect_equal(sum(prop.table(wgt)[y == "c"]), 39/118, tol = 0.0001, lower = 0.9) + expect_equal(sum(wgt), 1) + } + }) From d1ea21638fb657a6666ff7127846d77bb770267b Mon Sep 17 00:00:00 2001 From: Tim Bock Date: Mon, 9 Aug 2021 09:53:53 +1000 Subject: [PATCH 5/8] DS-3465 Dealing with constraints as strings --- R/weightingdialog.R | 6 ++---- inst/testdata/Cola stacked.sav | Bin 0 -> 88093 bytes man/WeightingDialog.Rd | 3 +++ tests/testthat/Combined data set.sav | Bin 0 -> 10655 bytes tests/testthat/test-weightingdialog.R | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 inst/testdata/Cola stacked.sav create mode 100644 tests/testthat/Combined data set.sav diff --git a/R/weightingdialog.R b/R/weightingdialog.R index 30fe67a..5268f72 100644 --- a/R/weightingdialog.R +++ b/R/weightingdialog.R @@ -92,10 +92,8 @@ computeWeightsDialog <- function(adjustment.variables, has.numerics, margins, in if (lower == "" & upper == "" & !has.numerics) stop("This should be processed via the existing Q algorithm and this code should not have been called.") # Bounds - if (lower == "") - lower = 0 - if (upper == "") - upper = Inf + lower = if (lower == "") lower = 0 else as.numeric(lower) + upper = if (upper == "") upper = Inf else as.numeric(upper) if (calfun == "logit") { upper = min(1000, upper)# Avoiding having a denominator if Inf in Phi_R diff --git a/inst/testdata/Cola stacked.sav b/inst/testdata/Cola stacked.sav new file mode 100644 index 0000000000000000000000000000000000000000..b022105ee9272e5ef1c4261e33ebe15a4840d8b8 GIT binary patch literal 88093 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͂+Dir}KZ**e)O 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 nT*RwNxx;Z>aN)oB_(uyxd&PJKTezYQ6DdF literal 0 HcmV?d00001 diff --git a/man/WeightingDialog.Rd b/man/WeightingDialog.Rd index 27b350c..b64f56b 100644 --- a/man/WeightingDialog.Rd +++ b/man/WeightingDialog.Rd @@ -12,6 +12,7 @@ WeightingDialog( lower = "", upper = "", calfun = c("Raking", "Linear", "Logit")[1], + force.to.n = TRUE, input.weight = NULL ) } @@ -30,6 +31,8 @@ WeightingDialog( \item{calfun}{The calibration function: Raking (Default), Linear, Quadratic.} +\item{force.to.n}{Force the sum of weights to equal the sample size.} + \item{input.weight}{An optional weight variable; if supplied, the created weight is created to be as close to this input.weight as possible} } diff --git a/tests/testthat/Combined data set.sav b/tests/testthat/Combined data set.sav new file mode 100644 index 0000000000000000000000000000000000000000..9b934d97c210f238c12575b1c605d24bf64b11df GIT binary patch literal 10655 zcmeHNOK%*<5vF6wqGTlz6ai5H9R{`!cA!W*5AKo*1Pw(|h5|_zMFBx_A=Xsy&h+#w zwZqkG_h4Oe2oJvGl4GvUU&s#%agirbWEdnlnd3CM-0DX?zWSB7963=ZKu1P8a?R0I%@xf{Z0FCB-f(P)##~ej<7Z5`DbW; zdM#QVs>A(~ZrRxsdzl-Rqv*BjH@l=i?a{{Q3_fA3K6&yu#t|fY)NdxQ@7+0k|744% zTHhQ`cbF-9Ls%yh*SAn1HK7N?~)u@fhXSWWw zE8DtF`}`F9Y(DEZl_^KVs4hpU>6_?fe}VuV8vl&Y5=9?a9R>ph;J%N~=P~$sd+XfY z=cDaOxii9U^ziqK`GrSKxvg$Q>#v@v(Qf%dS*ep>$S;cg-bl^O;PsdDOY1NC=6QdD zl{cbCJG&))YWKe~FMp_pc4jM&^3z{T3e~vtKFSv#D^vErH1m4=JbxehlWKhK)%@H# zJTokJ$xHtGZhmT0y?Wiw>*XJ8PMRIe;dN{InKi^{x7;Q^cu&TOugE+9-dBXb6JH(A zSLCM?Umed^l#3_6I-akne>m~g@q9(~kbLFp=EB0;Tc;lMZEc|)@Z=xdRW*I%>H+l$ zw1)aRdGf`0IhyQ5NoFgJt3iwTVzOkvUzz*JT41e76tYY#izXit~Sp zkq>3f_W>i+Lw?^e^22|L_uE^iAF3C=Z(YbQeKFcrlx35b=%=H;z45g9vzY(H%4yB( zC`BrcCdDq%2DZj?AwO^BeU`M}U&=2A>yqfDQk7j6*<}lt^ABYmN&J3S@{5V3py+A; z^)9q=Vp$jE7c-JC9U}iI|Jk}#6$XuPbu+IcRvp{XDSV%%{`p53gb$w!C%$p~`r{Md z9EuydW4l^Q{-RoR3Bx@HcnDuKsDA%#pXa-|ggKgXaPTevI{5ahf5_joFL5-@?O@Pc z+Mo9Ne}ASk=q!5vS7(tu#6h(8UoiNc)=m3s`z(IZn=ATreQP_Wzwu^@{=BngrS#s3 z{#+9&-YwCet1P8ANA%}yD@|^0Bxg6$n;R*9Zqe_p^sIe9b8~evX|OxqzhKT5KBe>t zKkQ8YZ2!U=k((R%aTY&r)2G|?31{L5nL?o_7g1QrBznH#UkiUFpW&%>r7ArbezlKL zS5?yKc2~M_WQF))R9zitRsCTf!_+m)lUA;=URAQb8j3t^<*K4bY-wJua#?UFu}={$d_BWsrQ;jE3C&T2P|LiwDPLby4I@r-9CmcO1uBEw+}M> zHyHhSAEO>C*0 znab^74oKeXbiDos;lZ)2f2~PB$i4o`)Y_;)`TKp0%I*)jKVRu7;;Rr}3~l`f`BLj2 z>~F@c|0;?Pcu^^9yk5ceI2IIfiNxgjy5(M^({x&}#5Bv-FKm*P%B%`%24g70Qcm9$1 zrCvYE4!A(<7ysbm)9MHRwfV>R?R7H0UaJFgvE+xvcdxVL;|Kk9qg?)p{Y&0HKnjoG z&-s7J@4q)A4He>xfsfX{fM05*o2eS$d<JPm_@_|3|BA8YE zJN&^m;$O)x#z!3R6J;MH~Z_e&qfk z4)_PH2lPK6Sv1Z*ZOUU(mlGxdBnxA5?ASS)gAHewnuYtHoD>7r5?x zyWHI`(1_agLI0xQT)>a(JN(3Q?;n7V@Xh`ad?x`vXgxLKmfyKQNy7ZL{hh=geXiX< z%>gU&}9izvv}BU%%*f0eoXU z27<-n~3{|m-<8t@09x4qv~rPVJD`V%Cl)-%aZ!GGEb{10rSe_?#d{VB!&FUR2*J^QC`EgZs}O z6lm`U1;;1r`1(TaAKp(fK1#m7WC1^@F*R7uzkGkmIsrdZ|2~uW8@_*JLH_}AAco`k zOMJ7~pAX}30d@T|=WiC=Uy%Ih+S~rg#y^Yw`BcAPqTqw$mj(A1q#yCW;9v9lAb$ZZ zbeN7mIe)Vte^mvBuIB4=7W5}z7ern5=l6%bEXZG~{%w92%zs&UKcW8A#TULHd}Kj> ra(z%YysI9;z447kqGkkp=HRY Date: Mon, 9 Aug 2021 19:06:12 +1000 Subject: [PATCH 6/8] Remove unused testing data files; DS-3466 [revdep skip] --- .gitignore | 1 + inst/testdata/Cola stacked.sav | Bin 88093 -> 0 bytes tests/testthat/Combined data set.sav | Bin 10655 -> 0 bytes 3 files changed, 1 insertion(+) delete mode 100644 inst/testdata/Cola stacked.sav delete mode 100644 tests/testthat/Combined data set.sav diff --git a/.gitignore b/.gitignore index 34579fd..f94754f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ inst/doc # testthat artifact tests/testthat/Rplots.pdf tests/testthat/Combined data set.sav +inst/testdata/Cola stacked.sav *.Rhistory diff --git a/inst/testdata/Cola stacked.sav b/inst/testdata/Cola stacked.sav deleted file mode 100644 index b022105ee9272e5ef1c4261e33ebe15a4840d8b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88093 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͂+Dir}KZ**e)O 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 nT*RwNxx;Z>aN)oB_(uyxd&PJKTezYQ6DdF diff --git a/tests/testthat/Combined data set.sav b/tests/testthat/Combined data set.sav deleted file mode 100644 index 9b934d97c210f238c12575b1c605d24bf64b11df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10655 zcmeHNOK%*<5vF6wqGTlz6ai5H9R{`!cA!W*5AKo*1Pw(|h5|_zMFBx_A=Xsy&h+#w zwZqkG_h4Oe2oJvGl4GvUU&s#%agirbWEdnlnd3CM-0DX?zWSB7963=ZKu1P8a?R0I%@xf{Z0FCB-f(P)##~ej<7Z5`DbW; zdM#QVs>A(~ZrRxsdzl-Rqv*BjH@l=i?a{{Q3_fA3K6&yu#t|fY)NdxQ@7+0k|744% zTHhQ`cbF-9Ls%yh*SAn1HK7N?~)u@fhXSWWw zE8DtF`}`F9Y(DEZl_^KVs4hpU>6_?fe}VuV8vl&Y5=9?a9R>ph;J%N~=P~$sd+XfY z=cDaOxii9U^ziqK`GrSKxvg$Q>#v@v(Qf%dS*ep>$S;cg-bl^O;PsdDOY1NC=6QdD zl{cbCJG&))YWKe~FMp_pc4jM&^3z{T3e~vtKFSv#D^vErH1m4=JbxehlWKhK)%@H# zJTokJ$xHtGZhmT0y?Wiw>*XJ8PMRIe;dN{InKi^{x7;Q^cu&TOugE+9-dBXb6JH(A zSLCM?Umed^l#3_6I-akne>m~g@q9(~kbLFp=EB0;Tc;lMZEc|)@Z=xdRW*I%>H+l$ zw1)aRdGf`0IhyQ5NoFgJt3iwTVzOkvUzz*JT41e76tYY#izXit~Sp zkq>3f_W>i+Lw?^e^22|L_uE^iAF3C=Z(YbQeKFcrlx35b=%=H;z45g9vzY(H%4yB( zC`BrcCdDq%2DZj?AwO^BeU`M}U&=2A>yqfDQk7j6*<}lt^ABYmN&J3S@{5V3py+A; z^)9q=Vp$jE7c-JC9U}iI|Jk}#6$XuPbu+IcRvp{XDSV%%{`p53gb$w!C%$p~`r{Md z9EuydW4l^Q{-RoR3Bx@HcnDuKsDA%#pXa-|ggKgXaPTevI{5ahf5_joFL5-@?O@Pc z+Mo9Ne}ASk=q!5vS7(tu#6h(8UoiNc)=m3s`z(IZn=ATreQP_Wzwu^@{=BngrS#s3 z{#+9&-YwCet1P8ANA%}yD@|^0Bxg6$n;R*9Zqe_p^sIe9b8~evX|OxqzhKT5KBe>t zKkQ8YZ2!U=k((R%aTY&r)2G|?31{L5nL?o_7g1QrBznH#UkiUFpW&%>r7ArbezlKL zS5?yKc2~M_WQF))R9zitRsCTf!_+m)lUA;=URAQb8j3t^<*K4bY-wJua#?UFu}={$d_BWsrQ;jE3C&T2P|LiwDPLby4I@r-9CmcO1uBEw+}M> zHyHhSAEO>C*0 znab^74oKeXbiDos;lZ)2f2~PB$i4o`)Y_;)`TKp0%I*)jKVRu7;;Rr}3~l`f`BLj2 z>~F@c|0;?Pcu^^9yk5ceI2IIfiNxgjy5(M^({x&}#5Bv-FKm*P%B%`%24g70Qcm9$1 zrCvYE4!A(<7ysbm)9MHRwfV>R?R7H0UaJFgvE+xvcdxVL;|Kk9qg?)p{Y&0HKnjoG z&-s7J@4q)A4He>xfsfX{fM05*o2eS$d<JPm_@_|3|BA8YE zJN&^m;$O)x#z!3R6J;MH~Z_e&qfk z4)_PH2lPK6Sv1Z*ZOUU(mlGxdBnxA5?ASS)gAHewnuYtHoD>7r5?x zyWHI`(1_agLI0xQT)>a(JN(3Q?;n7V@Xh`ad?x`vXgxLKmfyKQNy7ZL{hh=geXiX< z%>gU&}9izvv}BU%%*f0eoXU z27<-n~3{|m-<8t@09x4qv~rPVJD`V%Cl)-%aZ!GGEb{10rSe_?#d{VB!&FUR2*J^QC`EgZs}O z6lm`U1;;1r`1(TaAKp(fK1#m7WC1^@F*R7uzkGkmIsrdZ|2~uW8@_*JLH_}AAco`k zOMJ7~pAX}30d@T|=WiC=Uy%Ih+S~rg#y^Yw`BcAPqTqw$mj(A1q#yCW;9v9lAb$ZZ zbeN7mIe)Vte^mvBuIB4=7W5}z7ern5=l6%bEXZG~{%w92%zs&UKcW8A#TULHd}Kj> ra(z%YysI9;z447kqGkkp=HRY Date: Tue, 10 Aug 2021 10:27:09 +1000 Subject: [PATCH 7/8] Bump version [ci skip] --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 80e2ea3..53c1550 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: flipData Type: Package Title: Functions for extracting and describing data -Version: 1.4.0 +Version: 1.5.0 Author: Displayr Maintainer: Displayr Description: Functions for extracting data from formulas and From e131eafead2fb8eb20cf72f11ab213ab07525280 Mon Sep 17 00:00:00 2001 From: "Mathew W. McLean" Date: Tue, 10 Aug 2021 18:59:49 +1000 Subject: [PATCH 8/8] Fix typo in documentation; DS-3465 [revdep skip] --- R/weightingdialog.R | 5 +---- man/WeightingDialog.Rd | 2 +- tests/testthat/test-weightingdialog.R | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/R/weightingdialog.R b/R/weightingdialog.R index 5268f72..88582b7 100644 --- a/R/weightingdialog.R +++ b/R/weightingdialog.R @@ -6,15 +6,12 @@ #' @param numeric.targets the target mean for each numeric variable in numeric.variables #' @param lower A lower bound weight value (not guaranteed to be achieved). #' @param upper An upper bound weight value (not guaranteed to be achieved). -#' @param calfun The calibration function: Raking (Default), Linear, Quadratic. +#' @param calfun The calibration function: \code{"Raking"} (Default), \code{"Linear"}, or \code{"Logit"}. #' @param input.weight An optional weight variable; if supplied, the created weight is created to be as close #' to this input.weight as possible #' @param force.to.n Force the sum of weights to equal the sample size. -#' #' @return numeric A vector of weights #' @export - - WeightingDialog <- function(categorical.variables = NULL, categorical.targets = NULL, numeric.variables = NULL, diff --git a/man/WeightingDialog.Rd b/man/WeightingDialog.Rd index b64f56b..e10d864 100644 --- a/man/WeightingDialog.Rd +++ b/man/WeightingDialog.Rd @@ -29,7 +29,7 @@ WeightingDialog( \item{upper}{An upper bound weight value (not guaranteed to be achieved).} -\item{calfun}{The calibration function: Raking (Default), Linear, Quadratic.} +\item{calfun}{The calibration function: \code{"Raking"} (Default), \code{"Linear"}, or \code{"Logit"}.} \item{force.to.n}{Force the sum of weights to equal the sample size.} diff --git a/tests/testthat/test-weightingdialog.R b/tests/testthat/test-weightingdialog.R index 7fff71f..f38c616 100644 --- a/tests/testthat/test-weightingdialog.R +++ b/tests/testthat/test-weightingdialog.R @@ -40,7 +40,7 @@ test_that("Single Categorical adjustment variable", { expect_error(WeightingDialog(list(Age = input.age), variable.targets.age), "This should be processed via the existing Q algorithm and this code should not have been called.") - # Raking with trvial lower and upper values + # Raking with trivial lower and upper values wgt.calibrate = Calibrate(list(Age = input.age), variable.targets.age, package = "icarus", always.calibrate = TRUE) wgt.dialog = WeightingDialog(list(Age = input.age), variable.targets.age, lower = 0, upper = 1000) expect_equivalent(cor(wgt.calibrate, wgt.dialog), 1)