Skip to contents

For a non-probability sample (opt-in panel, volunteer or river sample) with no design weights, step_pseudoweight() estimates each unit's participation propensity \(\hat p\) against a probability reference_sample() and assigns the pseudo-weight \((1 - \hat{p})/\hat{p}\) (the participation odds; the adjusted logistic propensity of Wang, Valliant and Li 2021, after Elliott and Valliant 2017), which inflates each unit to the population. Their sum estimates the reference's estimated population size – it is unbiased for it, not equal to it, and varies from sample to sample like any other estimator. It stacks the non-probability sample and the reference internally (the participation indicator and the two samples' weights are built for you), fits the propensity, and returns the pseudo-weight on the non-probability units only; the reference is used to train the model and then dropped.

Usage

step_pseudoweight(
  spec,
  reference,
  formula,
  engine = c("logit", "tree", "forest", "boost"),
  num_classes = NULL,
  by = NULL,
  crossfit = NULL,
  crossfit_seed = NULL,
  id = NULL
)

Arguments

spec

a non-probability weighting_spec.

reference

a reference_sample() (the probability reference with its design weights). Pass the reference's replicate weights through reference_sample(replicates = ) to propagate its sampling variance through the recipe-aware bootstrap: each replicate refits the propensity from the paired reference replicate. Without them the reference is treated as fixed, so the bootstrap reflects only the variability of the non-probability sample (which it resamples as a with-replacement sample of units, a slightly conservative approximation when that sample is a large fraction of the population).

formula

one-sided formula of the covariates shared by both samples, e.g. ~ sex + age + region.

engine

propensity learner: "logit" (default), "tree", "forest" or "boost".

num_classes

NULL (default, direct 1/pi) or an integer: group the fitted propensities into that many quantile classes and use the class-average pseudo-weight, which is more robust to a misspecified model.

by

NULL (default), or a single column name: fit one participation model per domain, on that domain's units of both samples and on nothing else. The reference must carry the same domain column, and is split by it, so the pseudo-weights of a domain sum to that domain's reference total rather than to the national one – which is what lets a following domain-partitioned calibration start from a coherent input weight. Use it when the participation mechanism differs across domains (a covariate whose effect changes sign by region is the clear case), where a single additive national model misses the domain totals in both directions – measured on three domains with the slope changing sign: ~ dom + x landed at 4,258 / 3,530 / 4,803 against a truth of 4,022 / 4,033 / 3,945.

For engine = "logit" this is the fully interacted national model, ~ dom * (...), and gives the same weights to numerical precision – not a different estimator, but the practicable way to fit it: the interactions are never written out, a domain without enough units on either side is named instead of quietly degrading the whole fit, and the tree, forest and boost engines have no interaction syntax at all, so there segmenting is the only route. Each domain needs enough units on each side to fit its own model; those that do not are reported by name.

crossfit, crossfit_seed

optional K-fold cross-fitting of the propensity (recommended for the flexible learners), and its seed.

id

optional stable step id.

Value

the input weighting_spec with this step appended.

Details

The recipe must be a non-probability spec: weighting_spec(..., nonprob = TRUE). This step is the inverse-propensity (IPW) route; you can instead, or additionally, calibrate to a reference_sample() with step_calibrate() / step_model_calibration() (mass imputation / model-based), and combining both gives the doubly robust estimator.

References

Wang, L., Valliant, R. and Li, Y. (2021). Adjusted logistic propensity weighting methods for population inference using nonprobability volunteer-based epidemiologic cohorts. Statistics in Medicine 40(24), 5237-5250. doi:10.1002/sim.9122

Elliott, M. R. and Valliant, R. (2017). Inference for non-probability samples. Statistical Science 32(2), 249-264.

Examples

set.seed(1)
N   <- nrow(population)
# a biased volunteer sample (men over-participate) and a probability reference
vol <- population[rbinom(N, 1, plogis(-2 + 0.9 * (population$sex == "M"))) == 1,
                  c("region", "sex", "income")]
ref <- population[sample(N, 600), c("region", "sex")]
ref$d <- N / 600                                   # its design weights
fit <- weighting_spec(vol, base_weights = NULL, nonprob = TRUE) |>
  step_pseudoweight(reference = reference_sample(ref, "d"),
                    formula = ~ region + sex, engine = "logit") |>
  prep()
# the pseudo-weighted mean corrects the volunteer bias
c(naive = mean(vol$income),
  pseudo = weighted.mean(vol$income, fit$final_weight),
  truth = mean(population$income))
#>    naive   pseudo    truth 
#> 19353.58 18936.79 19298.11