Replicate Weights for Variance Estimation in Python
BRR, Jackknife, Bootstrap, and SDR methods for complex survey designs
Tutorials
Survey Weighting
Variance Estimation
Python
Learn how to create and adjust replicate weights for survey variance estimation using the svy library. Covers BRR, Jackknife (JKn and JK2), Bootstrap, and SDR methods with automatic propagation of weight adjustments.
Replicate weights provide a flexible approach to variance estimation for complex survey designs. Rather than relying on analytical formulas (Taylor linearization), replication methods estimate variance by repeatedly perturbing the sample weights and observing the resulting variation in estimates.
This tutorial assumes you’ve completed the Sample Selection and Weighting tutorials. We use the same World Bank synthetic sample data throughout.
When to Use Replicate Weights
Replicate weights are especially useful when:
Estimating non-linear statistics (medians, percentiles, ratios) where Taylor linearization may be inaccurate
The number of PSUs per stratum is small, making linearization-based variance estimates unstable
Sharing data with secondary analysts who may not have access to design details
Approach
Strengths
Limitations
Taylor linearization
Computationally efficient; no additional columns needed
Requires correct design specification; may be inaccurate for non-linear statistics
Replication
Flexible; works well for non-linear statistics; easy to share
Increases file size; computationally heavier for many replicates
Setting Up
import numpy as npimport polars as plimport svyrng = np.random.default_rng(12345)hld_data = svy.datasets.load(name="hld_sample_wb_2023")hld_sample = svy.Sample( data=hld_data, design=svy.Design(stratum=("geo1", "urbrur"), psu="ea", wgt="hhweight"),)print(hld_sample)
╭────────────── Sample ───────────────╮│Survey Data││ Rows : 8000 ││ Columns : 52 ││ Strata : 19 ││ PSUs : 320 ││││Survey Design││ Row index svy_row_index ││ Stratum (geo1, urbrur) ││ PSU ea ││ SSU None ││ Weight hhweight ││ With replacement False ││ Prob None ││ Hit None ││ MOS None ││ Population size None ││ Replicate weights None │╰─────────────────────────────────────╯
The World Bank sample includes a household weight (hhweight) computed from the selection probabilities. Although labeled as a survey weight in the dataset, no nonresponse adjustment or calibration has been applied — it is effectively a base weight. This makes it ideal for demonstrating the recommended workflow: create replicates from the base weight first, then apply adjustments that propagate automatically to both the main weight and the replicates.
Replication Methods Overview
svy supports five replication methods. The API is consistent across all of them — only the statistical method and its requirements differ:
Method
Function
Requirements
Typical Use
Bootstrap
create_bs_wgts()
≥ 2 PSUs per stratum
Most flexible; complex designs; non-linear statistics
Jackknife (JKn)
create_jk_wgts(paired=False)
≥ 1 PSU per stratum
General purpose; # replicates = # PSUs
Jackknife (JK2)
create_jk_wgts(paired=True)
2–3 PSUs per stratum
Paired designs; fewer replicates
BRR
create_brr_wgts()
Exactly 2 PSUs per stratum
Balanced half-samples
Fay-BRR
create_brr_wgts(fay_coef=...)
Exactly 2 PSUs per stratum
Damped BRR for stability
SDR
create_sdr_wgts()
Ordered/systematic samples
Systematic samples; time series
All methods share the same core parameters:
Parameter
Description
n_reps
Number of replicates (bootstrap and BRR; JKn/JK2 determine this automatically)
rep_prefix
Prefix for replicate weight column names (defaults to the active weight name)
rstate
Random state for reproducibility
drop_nulls
Drop rows with missing values in design columns before creation
Bootstrap
Bootstrap replication draws PSUs with replacement within each stratum. The Rao-Wu rescaled bootstrap adjusts weights to maintain unbiasedness under the sampling design. It is the most general method — it works with any number of PSUs per stratum (≥ 2) and handles non-linear statistics well.
The replicate weight columns are named automatically from the active weight: hhweight1, hhweight2, …, hhweight500. You can override this with rep_prefix:
For simple statistics (means, totals), 200–500 replicates usually suffice. For percentiles or other non-linear statistics, consider 1,000+. More replicates reduce Monte Carlo error but increase computation time and file size.
Jackknife Methods (JKn and JK2)
The jackknife estimates variance by systematically leaving out one PSU (or one group of PSUs) at a time and observing how the estimate changes. svy supports two variants controlled by the paired parameter.
JKn (delete-one-PSU) creates one replicate per PSU across the entire sample. In each replicate, one PSU is dropped and the remaining PSUs within that stratum are upweighted to compensate. The number of replicates equals the total number of PSUs — with many PSUs this can produce a large number of columns, but the method is very general.
# JKn: one replicate per PSUjkn_sample = hld_sample.weighting.create_jk_wgts(paired=False)
JK2 (paired jackknife) is designed for paired PSU designs (2–3 PSUs per variance stratum). It creates one replicate per stratum, where one PSU is deleted and the others upweighted. This produces far fewer replicates than JKn.
Variant
paired
# Replicates
Best for
JKn
False
Total # of PSUs
General purpose; moderate # of PSUs
JK2
True
# of variance strata
Paired designs; fewer replicates
JK2 requires 2–3 PSUs per stratum. Most survey designs have more than that, so you typically need to create variance strata first — new strata that pair PSUs together. The create_variance_strata() method handles this, including the common case where a stratum has an odd number of PSUs (it creates a triplet for the last three):
You can control how PSUs are paired with order_by (sort before pairing) or shuffle=True (random pairing with rstate for reproducibility). Pairing similar-sized PSUs together (e.g., order_by="pop_size") can improve the efficiency of the variance estimate.
Balanced Repeated Replication (BRR)
BRR constructs balanced half-samples using a Hadamard matrix. In each replicate, one PSU is selected from each stratum: the selected PSU’s weight is doubled while the other PSU receives zero weight. This creates a systematic set of perturbations that efficiently captures between-PSU variability.
BRR requires exactly 2 PSUs per stratum. If your design has more, use create_variance_strata(method="brr") to pair them first. Unlike JK2, BRR cannot handle odd PSU counts — every stratum must have an even number of PSUs.
The number of replicates defaults to the smallest Hadamard matrix size ≥ the number of strata.
# Pair PSUs first (BRR requires exactly 2 per stratum)brr_sample = hld_sample.weighting.create_variance_strata( method="brr", into="var_stratum",)# Then create BRR replicatesbrr_sample = brr_sample.weighting.create_brr_wgts(rep_prefix="brr_wgt")
Fay-BRR
Standard BRR can produce unstable estimates when PSU contributions vary greatly because it zeros out half the sample in each replicate. Fay-BRR dampens the perturbation using a coefficient \(\rho \in (0, 1)\):
Selected PSU weight: multiplied by \((2 - \rho)\)
Non-selected PSU weight: multiplied by \(\rho\)
Common choices are \(\rho = 0.3\) to \(0.5\). As \(\rho \to 0\), Fay-BRR approaches standard BRR; as \(\rho \to 1\), the perturbation vanishes.
# Fay-BRR with ρ = 0.5# Selected PSUs get weight × 1.5, non-selected get weight × 0.5fay_sample = brr_sample.weighting.create_brr_wgts(fay_coef=0.5)
Successive Difference Replication (SDR)
SDR is designed for systematic samples where units are ordered (e.g., by geography or time). It creates replicates based on successive differences between adjacent units, which better captures the correlation structure in ordered samples compared to methods that assume independent PSU selection.
The key feature of creating replicates early is that every subsequent weight adjustment automatically propagates to the replicate weights. This ensures that replication-based variance estimates reflect all sources of variability — not just sampling variability, but also uncertainty from nonresponse adjustment, calibration, and trimming.
When you call adjust(), rake(), calibrate(), poststratify(), trim(), or normalize(), svy applies the same adjustment logic to each replicate weight in the same pass as the main weight. The adjusted replicates are renamed to match the new main weight (e.g., nr_wgt → nr_wgt1, nr_wgt2, …).
Example: Full Adjustment Pipeline
Let’s walk through a complete pipeline using the bootstrap sample from above. We simulate nonresponse, then apply adjustment and raking — the replicates follow along automatically.
The design now shows final_wgt as the active weight with final_wgt1, …, final_wgt500 as the replicates — each one individually raked to the same control margins.
Verify: Replicates Match Controls
# Check that a few replicate weights hit the same margins as the main weightfor col in ["final_wgt", "final_wgt1", "final_wgt250", "final_wgt500"]: totals = hld_sample.data.group_by("statocc").agg( pl.col(col).sum().alias("total") ).sort("statocc") owned = totals.filter(pl.col("statocc") =="Owned")["total"][0]print(f" {col}: Owned total = {owned:,.1f} (target: 1,932,000)")
final_wgt: Owned total = 1,932,000.0 (target: 1,932,000)
final_wgt1: Owned total = 1,932,000.0 (target: 1,932,000)
final_wgt250: Owned total = 1,932,000.0 (target: 1,932,000)
final_wgt500: Owned total = 1,932,000.0 (target: 1,932,000)
Skipping Replicate Adjustment
In some cases — preliminary analysis, memory constraints, or externally managed replicates — you may want to adjust only the main weight:
If you skip replicate adjustment (ignore_reps=True), variance estimates computed from those replicates will not account for the additional variability introduced by the weight adjustment. This typically leads to underestimated standard errors.
Design Metadata
When you create replicate weights, svy stores metadata in Sample.design.rep_wgts:
This metadata is used automatically by estimation functions to compute replicate-based variance estimates.
Tip
When replicate weights are provided by the data producer (e.g., in DHS or ACS public-use files), register them directly via the RepWeights configuration in svy.Design() instead of creating them. See the Design object documentation for details.
Choosing a Replication Method
If your design has…
Recommended method
Exactly 2 PSUs per stratum
BRR (most efficient)
2–3 PSUs per stratum
JK2 (paired jackknife)
Varying PSUs per stratum
JKn or Bootstrap
Many strata, few PSUs each
Fay-BRR (dampened)
Systematic/ordered sample
SDR
Complex non-linear statistics
Bootstrap (≥ 500 reps)
Need to minimize file size
JK2 (fewest columns)
Multi-PSU strata needing BRR/JK2
create_variance_strata() first
Next Steps
With your replicate weights created and adjusted, you’re ready to compute estimates with proper variance estimation. Continue to the estimation tutorial.
Fay, R. E. (1989). Theory and application of replicate weighting for variance calculations. Proceedings of the Survey Research Methods Section, American Statistical Association, 212–217.
Judkins, D. R. (1990). Fay’s method for variance estimation. Journal of Official Statistics, 6(3), 223–239.
Rao, J. N. K., & Wu, C. F. J. (1988). Resampling inference with complex survey data. Journal of the American Statistical Association, 83(401), 231–241.
Valliant, R., Dever, J. A., & Kreuter, F. (2018). Practical Tools for Designing and Weighting Survey Samples (2nd ed.). Springer.