All writing

Should You Trim Your Weights? Look at One Number First

Trimming is sold as a free reduction in variance. Whether it helps or hurts depends almost entirely on the correlation between the weight and the outcome — and you can check that in a line of code.

Weight trimming is close to universal practice. Cap the weights at some multiple of the mean — 3×, 5×, whatever the house convention is — on the grounds that a handful of enormous weights inflate the variance and destabilise the estimates.

The justification is a bias–variance trade: trimming introduces bias in exchange for a reduction in variance, and if the variance saving is large enough the mean squared error falls. That framing is right. What is usually missing is any check on whether the trade is actually favourable for the data in front of you.

It often isn't. And the thing that determines the answer is measurable in one line.


Part 1 — The trade, stated properly

For an estimator of a target , mean squared error decomposes as:

Untrimmed inverse-probability weights are (under a correct response model) approximately unbiased, so the first term is near zero and all the error is variance. Trimming reduces the second term and inflates the first. Whether MSE improves depends on which moves faster.

The critical question is what those large weights are made of. A weight of 8 arises for one of two reasons:

  1. Signal. The respondent genuinely represents eight population units, because people like them are severely under-represented in the achieved sample. Capping that weight discards the correction and reintroduces the non-response bias the weight existed to remove.
  2. Noise. The weight is large because of an unstable raking cell, a small denominator, or estimation error in a response model. It carries no information about the population and only adds variance. Capping it costs nothing and helps.

Most real weights are a mixture. The question is which dominates — and the answer is not a matter of taste.


Part 2 — Three regimes, simulated

I simulated a population of 20,000 with an outcome driven by a latent covariate , and non-response also driven by , so that weighting is doing real work. Weights are inverse response propensities from a correctly specified model, normalised to mean 1. Trimming caps at a multiple of the mean and renormalises. 5,000 replications per regime.

Three regimes, differing only in how much of the weight variation is signal:

Regime A — strong non-response bias, clean weights

Response depends strongly on ; weights are exactly right. Mean correlation between weight and outcome: +0.263.

TrimBias (pp)SD (pp)RMSE (pp)deff
none−0.0020.4090.4091.349
−0.1130.4000.4151.305
−0.1810.3960.4361.289
−0.3150.3920.5031.264
−0.6120.3830.7221.224
−1.4240.3681.4711.154
1.5×−2.4280.3562.4541.100

Trimming never helps. Every cap raises RMSE, and by 2× the estimator is off by 1.4 percentage points on average — an error four times larger than the sampling standard deviation it was trying to reduce. Note the design effect obediently falls at every step. A house-style trim at 3× would have cut deff from 1.35 to 1.22, produced a tighter-looking confidence interval, and made the estimate substantially worse. The diagnostic everyone watches improves while the thing that matters degrades.

Regime B — weak non-response bias, noisy weights

Response depends only weakly on , and the weights carry multiplicative noise unrelated to the outcome. Correlation between weight and outcome: +0.029.

TrimBias (pp)SD (pp)RMSE (pp)deff
none0.0060.5150.5151.763
−0.0150.5010.5011.699
−0.0300.4940.4951.667
−0.0600.4820.4851.614
−0.1220.4610.4771.527
2.5×−0.1790.4450.4791.465
−0.2650.4240.5001.384
1.5×−0.4030.3980.5661.284

Here the folklore is vindicated: RMSE falls from 0.515 to 0.477 at a 3× cap, a 7% improvement, and the curve has the classic U-shape with an interior optimum. Trim too hard and it turns bad again.

Regime C — no non-response bias, pure weight noise

Weights vary, but the variation is entirely noise. Correlation with outcome: 0.000.

TrimBias (pp)SD (pp)RMSE (pp)deff
none0.0050.5730.5732.059
0.0070.5160.5161.753
0.0060.4920.4921.633
0.0050.4530.4531.457
1.5×0.0050.4270.4271.342

Bias never appears — there is nothing for the weights to correct — and RMSE falls monotonically. Trim as hard as you like. In this regime the weights are doing no work at all, and the honest question is why they are there.


Part 3 — The diagnostic

The three regimes differ in one measurable quantity: the correlation between the weight and the outcome, , computed over respondents.

Regimecorr(w, y)Optimal trimRMSE change from trimming
A+0.263nonestrictly worse
B+0.029−7%
C0.0001.5× or harder−25%

This is not a coincidence, and it is the same quantity that governs whether Kish's effective sample size is accurate — as derived in Section 2.9 of the companion article. Both results turn on the same structural fact:

When the weights are uncorrelated with the outcome, they carry no bias-correcting information for that outcome, and their variability is pure cost.

So the diagnostic is direct. Before trimming, compute for the outcomes that matter:

  • Near zero — the weights are not correcting anything for this variable. Trimming is close to free. (And it is worth asking what the weights are for.)
  • Materially non-zero — the weights are doing real work on this variable. Trimming discards it. Expect bias, and be sceptical of any variance improvement.

The awkward part

The correlation is outcome-specific, and a survey has many outcomes. A single weight variable might be uncorrelated with brand awareness and strongly correlated with income. Trimming that helps the first will damage the second, and you must apply one weight to the whole dataset.

There is no clean resolution. The practical response is to compute the correlation across your key outcomes, take the largest absolute value, and let that govern. If any headline measure is strongly weight-correlated, do not trim; accept the variance and report the design effect honestly.


Part 4 — Better options than trimming

Trimming is a blunt instrument, and there are several less destructive ways to deal with extreme weights.

Fix the weights instead of capping them. Extreme weights usually indicate a problem upstream: a raking cell with six respondents in it, a calibration margin too finely cut, a response model with a covariate it cannot support. Collapsing sparse categories before raking removes the extreme weights at source without discarding any correction. This is nearly always the right first move, and it is the one most often skipped.

Winsorise rather than truncate. Redistribute the excess weight over the remaining respondents so the calibration totals are preserved, rather than simply discarding it. This keeps the weighted sample size and the population totals intact, and is what most survey packages mean by "trimming" in their documentation.

Trim, then re-rake. Capping breaks calibration to the population margins. Re-running the raking after trimming restores the margins and pulls back some of the bias, at the cost of partially undoing the trim. Iterating this to convergence is the standard production approach, and it is meaningfully better than a single capping pass.

Report both. Compute the headline estimate trimmed and untrimmed. If they agree, the decision did not matter and you can say so. If they disagree, that disagreement is a finding about the stability of your survey, and it belongs in the technical annex rather than being resolved silently by a house convention.


Part 5 — Implementation

import numpy as np

def weight_outcome_corr(w, y):
    """The diagnostic: how much bias-correcting information is in the weights?"""
    return float(np.corrcoef(w, y)[0, 1])

def trim_weights(w, cap_multiple=3.0, renormalise=True):
    """Cap at a multiple of the mean weight. Returns the capped weights."""
    w = np.asarray(w, dtype=float)
    capped = np.minimum(w, cap_multiple * w.mean())
    return capped / capped.mean() * w.mean() if renormalise else capped

def design_effect(w):
    """Kish design effect from unequal weighting."""
    w = np.asarray(w, dtype=float)
    return len(w) * np.sum(w**2) / np.sum(w) ** 2

# Decide, rather than defaulting
r = weight_outcome_corr(w, y)
print(f"corr(w, y) = {r:+.3f}")
if abs(r) > 0.10:
    print("Weights carry real information for this outcome - do not trim.")
else:
    print("Weights largely uninformative here - trimming is likely to help.")

R, with re-raking after the trim — the production-grade version:

library(survey)

des <- svydesign(ids = ~psu, strata = ~stratum, weights = ~w, data = dat)
des <- calibrate(des, ~ age_band + region + sex, pop.totals)

# Trim, then restore the calibration margins that trimming broke
des_t <- trimWeights(des, lower = NULL, upper = 3 * mean(weights(des)),
                     strict = TRUE)   # strict = re-calibrate after trimming

# Compare - if these agree, the decision did not matter
svymean(~outcome, des)
svymean(~outcome, des_t)

strict = TRUE is the part that matters: without it, trimWeights caps and renormalises but leaves the calibration totals wrong.


Part 6 — Checklist

  1. Compute corr(w, y) before deciding. For every outcome you will report on, not just one.
  2. If any key outcome has a materially non-zero correlation, do not trim. The weights are doing the job you hired them for.
  3. Never trim by house convention alone. "We always cap at 3×" is not a methodological position; it is a habit that happens to be right in some datasets and actively harmful in others.
  4. Fix sparse cells before you cap weights. Extreme weights are usually a symptom of over-fine calibration margins, and collapsing categories removes them without cost.
  5. Re-rake after trimming. Capping breaks calibration; leaving it broken trades one bias for another.
  6. Do not use the design effect as evidence that trimming worked. Trimming always lowers deff — that is arithmetic, not validation. In Regime A, deff fell at every step while RMSE rose at every step.
  7. Report both estimates when they differ. A material gap between trimmed and untrimmed is information about your survey, not a decision to be made quietly.

Reproducing the simulations

import numpy as np
rng = np.random.default_rng(7717)

def run(resp_coef, noise_sd, trims, reps=5000, n_pop=20000):
    """resp_coef: strength of non-response on x. noise_sd: weight noise."""
    out = {t: [] for t in trims}
    for _ in range(reps):
        x = rng.normal(0, 1, n_pop)
        y = (rng.uniform(size=n_pop) < 1/(1+np.exp(-(0.3 + 0.9*x)))).astype(float)
        truth = y.mean()
        pr = 1/(1+np.exp(-(0.2 + resp_coef*x)))
        resp = rng.uniform(size=n_pop) < pr
        xs, ys = x[resp], y[resp]
        w = 1.0/(1/(1+np.exp(-(0.2 + resp_coef*xs))))
        if noise_sd:                       # weight noise unrelated to y
            w = w*np.exp(rng.normal(0, noise_sd, len(w)) - noise_sd**2/2)
        w = w/w.mean()
        for t in trims:
            wt = w if t is None else np.minimum(w, t)
            wt = wt/wt.mean()
            out[t].append(np.sum(wt*ys)/np.sum(wt) - truth)
    return {t: (np.mean(e)*100, np.std(e)*100,
                np.sqrt(np.mean(np.square(e)))*100) for t, e in out.items()}

trims = [None, 6.0, 5.0, 4.0, 3.0, 2.5, 2.0, 1.5]
regime_a = run(-1.10, 0.00, trims)   # strong bias, clean weights
regime_b = run(-0.15, 0.75, trims)   # weak bias, noisy weights
regime_c = run( 0.00, 0.85, trims)   # no bias, pure noise

Sources and further reading

  • Potter, F. (1990) "A study of procedures to identify and trim extreme sampling weights", Proceedings of the Survey Research Methods Section, ASA — the origin of several standard trimming rules, including their stated limitations.
  • Kish, L. (1992) "Weighting for unequal ", Journal of Official Statistics 8(2) — Kish's own account of when unequal weighting is worth its variance cost.
  • Little, R.J.A. & Vartivarian, S. (2005) "Does weighting for nonresponse increase the variance of survey means?", Survey Methodology 31(2) — directly on the question of when weighting pays for itself, and the source of the weight–outcome-correlation framing used here.
  • Valliant, R., Dever, J. & Kreuter, F. (2018) Practical Tools for Designing and Weighting Survey Samples, 2nd edn, Chapter 14 — the practical treatment of trimming and calibration, with worked R.