knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
Household surveys rarely sample households with equal probability. Urban areas, minority groups, or remote regions may be over- or under-sampled to improve precision. Each household is therefore assigned a sampling weight that records how many population households it represents.
If you compute the MPI without accounting for these weights, every sampled household counts equally — which gives biased estimates for the true population. With weights, a household with weight 3.2 contributes 3.2 times as much to H, A, and the indicator means as a household with weight 1.0.
Surveys also often use a complex design — stratified sampling (separate strata such as urban/rural) combined with cluster sampling (selecting geographic clusters, then households within them). Ignoring this structure leads to standard errors that are too small and confidence intervals that are too narrow.
mpindex supports both through the survey package.
install.packages("survey") # only needed once
library(mpindex) library(survey)
mpi_specs <- global_mpi_specs(uid = "uuid")
For this vignette we add synthetic survey columns to the built-in dataset. In real work these columns come from the survey microdata.
set.seed(42) n <- nrow(df_household) df_hh <- df_household df_hh$hh_weight <- runif(n, 0.8, 2.5) # sampling weight df_hh$strata <- sample(c("urban", "rural"), n, replace = TRUE) df_hh$psu <- sample(1:30, n, replace = TRUE) # primary sampling unit
Define the deprivation cutoffs (same as in the main vignette):
deprivations <- list( nutrition = deprived(undernourished == 1 & age < 70, .data = df_household_roster, collapse_fn = max), child_mortality = deprived(with_child_died == 1), year_schooling = deprived(completed_6yrs_schooling == 2, .data = df_household_roster, collapse_fn = max), school_attendance = deprived(attending_school == 2 & age %in% 5:24, .data = df_household_roster, collapse_fn = max), cooking_fuel = deprived(cooking_fuel %in% c(4:6, 9)), sanitation = deprived(toilet > 1), drinking_water = deprived(drinking_water == 2), electricity = deprived(electricity == 2), housing = deprived(roof %in% c(5, 7, 9) | walls %in% c(5, 8, 9, 99) == 2 | floor %in% c(5, 6, 9)), assets = deprived(!( (asset_tv + asset_telephone + asset_mobile_phone + asset_computer + asset_animal_cart + asset_bicycle + asset_motorcycle + asset_refrigerator) > 1 & (asset_car + asset_truck) > 0 )) )
The most common starting point: you have a weight column but no stratification or clustering. This arises when households are selected with unequal probability but the design has no explicit strata or clusters — for example, a probability-proportional-to-size (PPS) sample with a single stage of selection.
Pass only weight. No strata or cluster needed.
mpi_simple <- compute_mpi( df_hh, mpi_specs = mpi_specs, deprivations = deprivations, weight = "hh_weight" ) mpi_simple$index$k_33
You can also request standard errors. Because there is no cluster structure, variance is estimated under simple random sampling with replacement (the survey package default when ids = ~1):
mpi_simple_inf <- compute_mpi( df_hh, mpi_specs = mpi_specs, deprivations = deprivations, weight = "hh_weight", inference = TRUE ) mpi_simple_inf$index$k_33[, c("headcount_ratio", "headcount_ratio_se", "mpi", "mpi_se")]
The simplest way: tell compute_mpi() which columns in your data frame carry the weight, stratum, and cluster identifiers.
mpi_weighted <- compute_mpi( df_hh, mpi_specs = mpi_specs, deprivations = deprivations, weight = "hh_weight", strata = "strata", cluster = "psu" ) mpi_weighted$index$k_33
All four components of the output — $index, $contribution, $headcount_ratio, and $deprivation_matrix — now reflect population-weighted estimates.
A finite-population correction can also be supplied if your sampling frame contains the stratum sizes:
compute_mpi( df_hh, mpi_specs = mpi_specs, deprivations = deprivations, weight = "hh_weight", strata = "strata", cluster = "psu", fpc = "stratum_size" )
svydesign objectIf you already have a survey::svydesign() object — or prefer to specify the design once and reuse it — pass it via survey_design:
svy <- svydesign( ids = ~ psu, strata = ~ strata, weights = ~ hh_weight, nest = TRUE, # PSU IDs restart within each stratum data = df_hh ) mpi_from_design <- compute_mpi( df_hh, mpi_specs = mpi_specs, deprivations = deprivations, survey_design = svy ) mpi_from_design$index$k_33
Both options produce identical point estimates.
Set inference = TRUE to append design-based standard errors and 95% confidence intervals alongside every point estimate. The intervals use the normal approximation and are clamped to [0, 1].
mpi_inference <- compute_mpi( df_hh, mpi_specs = mpi_specs, deprivations = deprivations, weight = "hh_weight", strata = "strata", cluster = "psu", inference = TRUE ) mpi_inference$index$k_33
The extra columns follow a consistent naming pattern:
| Column | Meaning |
|--------|---------|
| headcount_ratio | Point estimate for H |
| headcount_ratio_se | Design-based standard error |
| headcount_ratio_ci_low | Lower bound of CI |
| headcount_ratio_ci_high | Upper bound of CI |
The same pattern applies to intensity, mpi, and every indicator column in $headcount_ratio.
Change the confidence level with ci_level:
compute_mpi(..., inference = TRUE, ci_level = 0.90) # 90% CI
Combine survey weighting with by to get group-specific weighted estimates. Each group's H, A, and MPI are computed using only the design rows in that group.
mpi_by_class <- compute_mpi( df_hh, mpi_specs = mpi_specs, deprivations = deprivations, weight = "hh_weight", by = class, inference = TRUE ) mpi_by_class$index$k_33
It is instructive to compare weighted and unweighted estimates. When the sampling design is informative (i.e. selection probability is correlated with poverty status), the differences can be substantial.
mpi_unweighted <- compute_mpi(df_household, mpi_specs, deprivations) cat("Unweighted H:", round(mpi_unweighted$index$k_33$headcount_ratio, 4), "\n") cat("Weighted H:", round(mpi_weighted$index$k_33$headcount_ratio, 4), "\n")
The same survey arguments work when using a pre-assembled profile (list of define_deprivation() outputs) passed to compute_mpi():
mpi_result <- compute_mpi( df_hh, mpi_specs = mpi_specs, deprivations = deprivation_profile, # pre-assembled list from define_deprivation() weight = "hh_weight", strata = "strata", cluster = "psu", inference = TRUE )
save_mpi() works identically whether the output is weighted or not. The SE and CI columns, when present, are written to the same sheets alongside the point estimates.
save_mpi(mpi_inference, mpi_specs = mpi_specs, filename = "MPI Weighted Results")
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.