Part III Chapter 8
Field Guide: Six Surveys, Declared
Design facts, declaration code, and known traps for six public surveys, generated from their design manifests.
DataACS · CPS ASEC · NHIS · NHANES · BRFSS · ATUS
You have the file. The codebook lists a weight, and near it a stratum, a PSU, and perhaps eighty or a hundred and sixty more columns whose names end in numbers. Which of them go into svyset, or svydesign, or svy.Design, and what happens if you get it wrong? The file will not say, and neither will the software: it accepts most wrong declarations and prints a standard error. This chapter answers the question for the six surveys the book uses. It opens with the two ways a wrong declaration announces itself, silently and loudly, and each guide then states one number for what the wrong declaration would have cost.
Every September the Census Bureau publishes the share of Americans who went without health insurance for the whole of the previous year, estimated from the Current Population Survey's Annual Social and Economic Supplement, and every September someone sets out to reproduce it. The 2025 file gives them what IPUMS documents: the person weight ASECWT and its 160160 replicate weightsEstimandNumber of person (and household) replicate weights in the CPS ASECVarianceNone reportedSourcedesign.json: ipums/analysis/cps/metadata/cps_asec.design.json replicate weights. Ask svy (version 0.28, the version tested here) for the share uninsured in calendar 2024 twice, once with the default estimation call and once with method="replication" and variance_center="estimate". Both calls return 8.0%8.0%EstimandShare of persons uninsured for all of calendar year 2024 (store flag uninsured_ly), CPS ASEC 202595% CI7.8%–8.3% (t, df = 159)n141,911WeightASECWTVarianceSuccessive-difference replication, 160 replicate weightsSourceIPUMS CPS ASEC 2025 (ipums/analysis/cps/cps_asec and cps_asec_repwt, part_2020_2025)External benchmarkStore benchmark log reproduces Census's published all-year uninsured rates for CY2022 and CY2023Notesvy, method='replication', variance_center='estimate'; equals the hand formula (4/160) x sum of squared deviations. Both look like a successful replication. The default call reports 141,910141,910 degrees of freedomEstimandDegrees of freedom reported by svy's default call on the CPS ASEC replicate design (n - 1)VarianceNone reportedSourceIPUMS CPS ASEC 2025 (ipums/analysis/cps/cps_asec and cps_asec_repwt, part_2020_2025) degrees of freedom and a standard error of 0.090.09 percentage pointsEstimandSE that svy's default estimation call reports for the same estimate, silently ignoring the declared replicate weightsn141,911VarianceWeights only: computed without the survey design, so not a design-based standard errorSourceIPUMS CPS ASEC 2025 (ipums/analysis/cps/cps_asec and cps_asec_repwt, part_2020_2025)NoteDefault call: Taylor linearization treating each person as a PSU, df = n - 1. percentage points; the replication call reports 159159 degrees of freedomEstimandDesign degrees of freedom for CPS ASEC replicate-weight inferenceVarianceNone reportedSourcedesign.json: ipums/analysis/cps/metadata/cps_asec.design.jsonNote160 replicates - 1, per IPUMS CPS repwt FAQ degrees of freedom and 0.110.11 percentage pointsEstimandReplicate-weight SE of the CPS ASEC 2025 all-year uninsured sharen141,911VarianceSuccessive-difference replication, 160 replicate weightsSourceIPUMS CPS ASEC 2025 (ipums/analysis/cps/cps_asec and cps_asec_repwt, part_2020_2025), 1.30×1.30×EstimandReplicate SE divided by the default-call SE, CPS ASEC 2025 uninsured shareVarianceNone reportedSourceIPUMS CPS ASEC 2025 (ipums/analysis/cps/cps_asec and cps_asec_repwt, part_2020_2025) the default value. Only the second matches the Census Bureau's formula computed by hand. The first number gives the default call away: it ignored the declared replicate weights and linearized as if every person were an independent draw, so its degrees of freedom are the sample size minus one. The interval is 8.0% (95% CI 7.8%–8.3%)8.0%EstimandShare of persons uninsured for all of calendar year 2024 (store flag uninsured_ly), CPS ASEC 202595% CI7.8%–8.3% (t, df = 159)n141,911WeightASECWTVarianceSuccessive-difference replication, 160 replicate weightsSourceIPUMS CPS ASEC 2025 (ipums/analysis/cps/cps_asec and cps_asec_repwt, part_2020_2025)External benchmarkStore benchmark log reproduces Census's published all-year uninsured rates for CY2022 and CY2023Notesvy, method='replication', variance_center='estimate'; equals the hand formula (4/160) x sum of squared deviations. Nothing warned. Declaring a design and using it are different steps, and a year-over-year change that clears the first standard error need not clear the second.
The second failure is loud. Declare BRFSS 2024 as CDC documents it, with the final weight, the strata _STSTR, and the PSU _PSU, and ask for any national prevalence. R's survey package stops, and svy raises a SingletonError: 110110 strataEstimandStrata containing a single PSU (one respondent) in the full BRFSS 2024 fileVarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) strata in the full national file hold a single respondent, and a stratum with one PSU has no within-stratum variation to measure. Code that silently skips such strata, as many hand-rolled formulas do, treats them as contributing no variance at all. The declaration is incomplete until it includes a rule for single-PSU strata.
The six guides below each declare one current release: what it is and whom it covers, which weight, which variance method with which constant and degrees of freedom, what to do about lonely PSUs and pooled years, where the series break, and the traps that catch careful analysts. Each opens with the question a researcher in one field brings to that survey, because the trap is usually hiding inside that question. Jump to a survey: ACS, CPS ASEC, NHIS, ATUS, NHANES, BRFSS.
How to read a guide
Each guide is a table with three columns: the item, the declaration, and its provenance. The build script generates the tables from the data pipeline's design manifests, the producers' documentation, and counts taken from the data, and provenance takes one of six forms: design.json, a machine-readable field of the dataset's design manifest; design.json notes, the manifest's free text, which is where most of the pipeline's datasets still keep their variance tier, lonely-PSU rule, pooling rule, and series breaks; producer, documentation from the Census Bureau, BLS, NCHS, CDC, or IPUMS, read on the date in the "Last verified" row; computed from data; verified in this build, a behavior the script confirmed by running code; and book guidance, an editorial recommendation where neither manifest nor producer states a rule.
Each guide carries its declaration in Python (svy), R (survey), and Stata, folded into a block below the table. The Python and R declarations for NHIS, NHANES, BRFSS, ATUS, and CPS ASEC were executed against the book's store and give the same estimates and standard errors; the ACS declarations were checked on a synthetic frame with the same column names, not on the three-gigabyte replicate file; the Stata declarations follow the producers' published examples and were not executed, because Stata is not installed on the build machine.
A variance tier is a property of the extract, not a choice. Replicate designs (ACS, CPS ASEC) and Taylor designs (NHIS, NHANES, BRFSS) support design-based uncertainty. The book's ATUS extract carries weights only, so a standard error computed from it is not design-based, and nothing in the extract says whether it errs high or low.
Variable names in the code
The code mixes three kinds of name, and a copy has to keep them apart. In the ACS, CPS ASEC, NHIS, and ATUS snippets, UPPERCASE names are IPUMS variables. In the NHANES snippets they are NCHS names, except CYCLE_YEAR, which the book's store adds. The BRFSS snippets use the store's names: xststr, xpsu, and xllcpwt are CDC's _STSTR, _PSU, and _LLCPWT, and iyear and Health are harmonized store variables; Health has two levels, and "Poor" means fair or poor. Lowercase outcomes such as uninsured, uninsured_ly, current_smoker, and htn_measured are derived in the store, and fairpoor is built in the snippet itself; an extract of your own has to define them. Within each survey, the three languages use the same target, the same rule for missing outcomes, and the same variance method.
Six surveys at a glance
Predict first
The ACS has by far the most records of the six surveys and NHANES examines the fewest people. Rank the six by design degrees of freedom, the number of independent pieces of design information each release carries. Is the order the same as the order of record counts?
Six surveys at a glance
What a row represents, which weight, and where the uncertainty comes from
| Survey | A row is | Canonical weight | Variance method | Independent units | Design df | Tier in the store |
|---|---|---|---|---|---|---|
| ACS 2024 1-year | a person (households: HHWT on PERNUM = 1) | PERWT | successive difference replication | 80 replicates | 79 | replicate |
| CPS ASEC 2025 | a person (households: ASECWTH) | ASECWT | SDR and modified half-sample replication | 160 replicates | 159 | replicate |
| NHIS 2024 | a sample adult or sample child | SAMPWEIGHT | Taylor linearization | 662 PSUs in 52 strata | 610 (rule of thumb) | taylor |
| ATUS 2024 | a person-day (one diary day) | WT06 | producer: 160 replicates; store: weights only | none in the store | not available | weights only (no design-based SE) |
| NHANES Aug 2021–Aug 2023 | a person (exam or interview) | WTMEC2YR or WTINT2YR | Taylor linearization | 30 PSUs in 15 strata | 15 | taylor |
| BRFSS 2024 | an adult respondent | _LLCPWT | Taylor linearization | 457,670 PSUs (one per respondent) in 2,393 strata | 455,277 | taylor |
Figure 8.1 separates things that the phrase "complex survey" lumps together. Two surveys carry their design entirely in replicate weights. Three carry it in strata and PSUs, and they could hardly be more different: NHANES samples a few dozen counties, while BRFSS treats each respondent as a sampling unit. The sixth, as stored, carries no design at all. Each guide below ends its opening with one number for what the wrong declaration costs, and the numbers are as different as the designs.
ACS 2024 1-year
An economist who needs a state-by-year panel of uninsured rates, or a wage regression with a million workers and occupation fixed effects, comes to the American Community Survey because no other survey is large enough, and brings a question the sample size seems to settle: with three million records, does the design still matter? The trap that catches careful analysts is the published margin of error. The public-use microdata are a subsample of the full ACS, so a correct replicate standard error from the PUMS will not reproduce the margin the Census Bureau publishes from the full sample, and an analyst who reads the gap as a failed replication goes looking for a bug that is not there.
The design matters at any sample size. Lab 3 estimates the national uninsured rate among adults aged 19 to 64 from 1,871,4041,871,404 countEstimandUnweighted sample size: civilian noninstitutionalized adults aged 19-64 in the 50 states and DC, 2024 (IPUMS approximation: excludes institutional group quarters and the Armed Forces).WeightPERWTVarianceNone reportedSourceIPUMS USA, ACS 2024 1-year sample (analysis/usa/acs + acs_repwt, part_2020_2024.parquet; PERWT and REPWTP1-80) records; the replicate standard error is 2.57×2.57× ratio of standard errorsEstimandSE(SDR) / SE(naive iid) for the pooled national rate.WeightPERWTVarianceSuccessive-difference replication, 80 replicate weightsSourceIPUMS USA, ACS 2024 1-year sample (analysis/usa/acs + acs_repwt, part_2020_2024.parquet; PERWT and REPWTP1-80) the standard error that treats those records as independent draws, and the median state's is 1.59×1.59× ratio of standard errorsEstimandMedian across the 51 states of SE(SDR) / SE(naive iid).WeightPERWTVarianceSuccessive-difference replication, 80 replicate weightsSourceIPUMS USA, ACS 2024 1-year sample (analysis/usa/acs + acs_repwt, part_2020_2024.parquet; PERWT and REPWTP1-80)Notenaive iid SE = sqrt(p(1-p)/n).. The silent failure of the opening recurs here: for Texas, svy's default call reports a standard error of 0.140.14 percentage points (standard error)EstimandUninsured rate among civilian noninstitutionalized adults aged 19-64 in the 50 states and DC, 2024 (IPUMS approximation: excludes institutional group quarters and the Armed Forces): Texas, SE from svy 0.28's default mean() call with replicate weights declared.n161,135WeightPERWTVarianceTaylor linearization (design-based)SourceIPUMS USA, ACS 2024 1-year sample (analysis/usa/acs + acs_repwt, part_2020_2024.parquet; PERWT and REPWTP1-80)Notesvy silently ignores the declared replicate weights and linearizes with each person as a PSU. percentage points with 161,134161,134 countEstimandDegrees of freedom reported by the same default svy call (Texas): n - 1.WeightPERWTVarianceTaylor linearization (design-based)SourceIPUMS USA, ACS 2024 1-year sample (analysis/usa/acs + acs_repwt, part_2020_2024.parquet; PERWT and REPWTP1-80) degrees of freedom, and the replication call 0.170.17 percentage points (standard error)EstimandUninsured rate among civilian noninstitutionalized adults aged 19-64 in the 50 states and DC, 2024 (IPUMS approximation: excludes institutional group quarters and the Armed Forces): Texas, SE from svy with method='replication', variance_center='estimate'.n161,135WeightPERWTVarianceSuccessive-difference replication, 80 replicate weightsSourceIPUMS USA, ACS 2024 1-year sample (analysis/usa/acs + acs_repwt, part_2020_2024.parquet; PERWT and REPWTP1-80) with 7979 degrees of freedomEstimandDesign degrees of freedom for ACS replicate-weight inference (replicates minus 1)VarianceNone reportedSourcedesign.json: ipums/analysis/usa/metadata/acs.design.jsonNote80 replicates - 1, per IPUMS USA repwt FAQ.
The 2024 1-year sample holds 3,422,8883,422,888 person recordsEstimandPerson records in the ACS 2024 1-year sample (IPUMS USA)VarianceNone reportedSourceIPUMS USA ACS 2024 1-year (ipums/analysis/usa/acs/part_2020_2024.parquet) person records in the IPUMS extract. Its public design lives entirely in replicate weights: 8080 replicate weightsEstimandNumber of person (and household) SDR replicate weights in the ACS 1-year PUMSVarianceNone reportedSourcedesign.json: ipums/analysis/usa/metadata/acs.design.json person weights and as many household weights, built by successive difference replication. The variance is the constant 4/804/80EstimandSDR variance constant multiplying the sum of squared replicate deviations (ACS)VarianceNone reportedSourcedesign.json: ipums/analysis/usa/metadata/acs.design.json times the sum of squared deviations of the replicate estimates from the full-sample estimate, with 7979 degrees of freedomEstimandDesign degrees of freedom for ACS replicate-weight inference (replicates minus 1)VarianceNone reportedSourcedesign.json: ipums/analysis/usa/metadata/acs.design.jsonNote80 replicates - 1, per IPUMS USA repwt FAQ degrees of freedom. There are no strata or PSUs to declare alongside them: IPUMS says to treat the sample as a single stratum. Person estimates use PERWT; household estimates use HHWT on the first person of each household. Figure 8.2 lists each item of the declaration with its provenance.
ACS 2024 1-year: declared
IPUMS USA person file with the 80-replicate companion file
| Item | Declaration | Provenance |
|---|---|---|
| Pinned release | ACS 2024 1-year sample, IPUMS USA (SAMPLE = 202401) | computed from data |
| Records | 3,422,888 person records in the 2024 sample | computed from data |
| Universe | Persons in housing units and group quarters (2005, the first ACS year, covers the household population only) | design.json notes |
| Canonical weight | PERWT; person weight; household-level tabs use HHWT on PERNUM=1 | design.json |
| Alternate weights | HHWT (household) | design.json |
| Variance method | Replicate: successive difference replication | design.json |
| Replicate weights | REPWTP1–REPWTP80 (person) and REPWT1–REPWT80 (household), in the companion file usa/acs_repwt joined on SAMPLE, SERIAL, PERNUM | design.json |
| Variance formula | (4/80) × Σ_r (θ_r − θ̂)², deviations taken from the full-sample estimate (the mse option) | design.json |
| Design df | 79 (80 replicates - 1, per IPUMS USA repwt FAQ) | design.json |
| Strata and PSUs | None declared with the replicates: treat the sample as one stratum with no PSU. The extract also carries IPUMS STRATA and CLUSTER for Taylor linearization; the book uses the replicates | producer: IPUMS USA repwt FAQ; acs.dictionary.json |
| Lonely-PSU rule | Not applicable: no PSUs are declared | book guidance |
| Pooling rule | Not recorded. For a multi-year period prefer the ACS 5-year sample; to pool k one-year samples, divide PERWT and every replicate weight by k before estimating totals (means and shares are unchanged) | book guidance |
| Series breaks | 2005 = household population only (no group quarters). 2020 1-year is the experimental release. PUMA boundaries change at 2012 and 2022 vintages. | design.json notes |
| Negative replicate values | negative replicate values may occur under SDR (explicitly documented in the CPS FAQ; the USA FAQ does not address it) | design.json |
| Trap: svy default call | The default estimation call ignores declared replicate weights and returns a Taylor SE with df = n − 1. Pass method="replication" and variance_center="estimate", then assert df = 79 | verified in this build (synthetic frame) |
| Trap: bare REPWTP | IPUMS extracts can carry a variable named REPWTP (a flag): select REPWTP1–REPWTP80 by name, never with a wildcard | producer: IPUMS USA repwt FAQ |
| Trap: PUMS is a subsample | Replicate SEs from the PUMS will not reproduce the margins of error Census publishes from the full ACS sample | book guidance |
| Last verified | Replicate block verified 2026-07-11 against https://usa.ipums.org/usa/repwt.shtml; FAQ re-read 2026-09-10 | design.json; this build |
Declare it in Python, R, and Stata
# Paths point at the book's store; adapt them to your own extract.
import polars as pl
import svy
keys = ["SAMPLE", "SERIAL", "PERNUM"]
acs2024 = pl.col("SAMPLE") == 202401 # IPUMS sample code of the 2024 1-year file
p = (
pl.scan_parquet("ipums/analysis/usa/acs/part_2020_2024.parquet")
.filter(acs2024)
.select(keys + ["PERWT", "uninsured"])
)
reps = [f"REPWTP{i}" for i in range(1, 81)] # by name, never a REPWTP* wildcard
r = (
pl.scan_parquet("ipums/analysis/usa/acs_repwt/part_2020_2024.parquet")
.filter(acs2024)
.select(keys + reps)
)
d = p.join(r, on=keys, how="inner").collect()
rep = svy.SdrWgts(prefix="REPWTP", n_reps=80)
s = svy.Sample(d, design=svy.Design(wgt="PERWT", rep_wgts=rep))
est = s.estimation.mean("uninsured", method="replication", variance_center="estimate", drop_nulls=True)
assert est.to_dicts()[0]["df"] == 79 # the default call would silently report n - 1# Paths point at the book's store; adapt them to your own extract.
library(arrow)
library(dplyr)
library(survey)
keys <- c("SAMPLE", "SERIAL", "PERNUM")
p <- open_dataset("ipums/analysis/usa/acs/part_2020_2024.parquet") |>
filter(SAMPLE == 202401) |>
select(all_of(c(keys, "PERWT", "uninsured"))) |>
collect()
r <- open_dataset("ipums/analysis/usa/acs_repwt/part_2020_2024.parquet") |>
filter(SAMPLE == 202401) |>
select(all_of(c(keys, paste0("REPWTP", 1:80)))) |>
collect()
d <- inner_join(p, r, by = keys)
des <- svrepdesign(data = d, weights = ~PERWT, repweights = "^REPWTP[0-9]+$",
type = "successive-difference", mse = TRUE) # scale 4/80, df 79
svymean(~uninsured, des, na.rm = TRUE)* IPUMS USA's documented declaration (Stata 12+); list replicate weights by range.
svyset [pweight=perwt], vce(sdr) sdrweight(repwtp1-repwtp80) dof(79) mse
svy: mean uninsuredThe assertion in the Python declaration turns the silent failure of the default call into a loud one; the build script confirmed the failure on frames laid out like the ACS and the ASEC.
CPS ASEC 2025
A political scientist who has estimated turnout from the November supplement comes to the March file for the income, poverty, and coverage measures the voting file lacks, and meets 160160 replicate weightsEstimandNumber of person (and household) replicate weights in the CPS ASECVarianceNone reportedSourcedesign.json: ipums/analysis/cps/metadata/cps_asec.design.json columns the voting file never had. The Annual Social and Economic Supplement is the source of the official income, poverty, and health-insurance statistics; it is fielded in the first months of the year and asks about the year before, so the 2025 file describes calendar 2024. Its trap is the sign of the replicate weights. Some are negative, Stata refuses negative probability weights, and an analyst who meets the error is tempted to truncate or drop the offending replicates. They are legitimate for variance estimation, which is why IPUMS declares them as importance weights in Stata (Figure 8.3). The cost of ignoring them altogether is the opening's number: a standard error 1.30×1.30×EstimandReplicate SE divided by the default-call SE, CPS ASEC 2025 uninsured shareVarianceNone reportedSourceIPUMS CPS ASEC 2025 (ipums/analysis/cps/cps_asec and cps_asec_repwt, part_2020_2025) too small for the uninsured share, and a sample-size degrees of freedom in place of 159159 degrees of freedomEstimandDesign degrees of freedom for CPS ASEC replicate-weight inferenceVarianceNone reportedSourcedesign.json: ipums/analysis/cps/metadata/cps_asec.design.jsonNote160 replicates - 1, per IPUMS CPS repwt FAQ.
The IPUMS extract has 142,125142,125 person recordsEstimandPerson records with a positive ASECWT, CPS ASEC 2025VarianceNone reportedSourceIPUMS CPS ASEC 2025 (ipums/analysis/cps/cps_asec and cps_asec_repwt, part_2020_2025) person records with a positive supplement weight. Its 160160 replicate weightsEstimandNumber of person (and household) replicate weights in the CPS ASECVarianceNone reportedSourcedesign.json: ipums/analysis/cps/metadata/cps_asec.design.json replicate weights combine successive difference replication in self-representing strata with modified half-sample replication elsewhere; the variance constant is 4/1604/160EstimandReplicate variance constant (CPS ASEC)VarianceNone reportedSourcedesign.json: ipums/analysis/cps/metadata/cps_asec.design.json, and the degrees of freedom are 159159 degrees of freedomEstimandDesign degrees of freedom for CPS ASEC replicate-weight inferenceVarianceNone reportedSourcedesign.json: ipums/analysis/cps/metadata/cps_asec.design.jsonNote160 replicates - 1, per IPUMS CPS repwt FAQ.
CPS ASEC 2025: declared
IPUMS CPS ASEC person file with the 160-replicate companion file
| Item | Declaration | Provenance |
|---|---|---|
| Pinned release | CPS ASEC 2025, IPUMS CPS (YEAR = 2025); income and last-year coverage items refer to calendar year 2024 | producer: IPUMS CPS |
| Records | 142,125 person records with a positive ASECWT | computed from data |
| Universe | Noninstitutionalized persons in the 50 states and DC who are civilian adults (15 and older) or live with one; Armed Forces members living with their families are included, those in barracks are not | producer: Census ASEC documentation |
| Sample note | Includes the CHIP expansion sample (about 10,000 extra eligible housing units, part of the CPS since July 2001) to improve state estimates of children's coverage | producer: Census ASEC documentation |
| Canonical weight | ASECWT; person weight; household-level tabs use ASECWTH on PERNUM=1 | design.json |
| Alternate weights | ASECWTH (household) | design.json |
| Variance method | Replicate: successive difference replication method (for cases in self-representing strata) and the modified half-sample technique (for cases in non-self-representing strata) | design.json |
| Replicate weights | REPWTP1–REPWTP160 (person) and REPWT1–REPWT160 (household), in the companion file cps/cps_asec_repwt joined on YEAR, SERIAL, PERNUM | design.json |
| Variance formula | (4/160) × Σ_r (θ_r − θ̂)², deviations taken from the full-sample estimate | design.json |
| Design df | 159 (160 replicates - 1, per IPUMS CPS repwt FAQ); replicate weights cover 2005+ only | design.json |
| Strata and PSUs | None declared with the replicates | producer: IPUMS CPS repwt FAQ |
| Lonely-PSU rule | Not applicable: no PSUs are declared | book guidance |
| Pooling rule | Not recorded. To pool k ASEC years, divide ASECWT and every replicate weight by k before estimating totals (means and shares are unchanged) | book guidance |
| Series breaks | 2014 income redesign and 2019 processing change are series breaks. Variable availability differs by decade part (see availability matrix). A 2020-Census-based CPS sample began phasing in with April 2025 and completes in July 2026 (BLS expects a negligible effect on estimates) | design.json notes; producer: BLS |
| Negative replicate values | legitimate; for variance estimation only (use iweight-style handling); 132 negative replicate values among the 2025 person records. Stata declares iweights for this reason | design.json; computed from data; producer: IPUMS CPS repwt FAQ |
| Trap: svy default call | Verified on the 2025 file: the default call reports a Taylor SE with df = 141,910 (n − 1); the replicate call reports df = 159 | verified in this build (real data) |
| Trap: survey year | YEAR is the survey year; income, poverty, and last-year coverage describe the previous calendar year | producer: IPUMS CPS |
| Last verified | Replicate block verified 2026-07-11 against https://cps.ipums.org/cps/repwt.shtml; FAQ re-read 2026-09-10 | design.json; this build |
Declare it in Python, R, and Stata
# Paths point at the book's store; adapt them to your own extract.
import polars as pl
import svy
keys = ["YEAR", "SERIAL", "PERNUM"]
p = (
pl.scan_parquet("ipums/analysis/cps/cps_asec/part_2020_2025.parquet")
.filter(pl.col("YEAR") == 2025)
.select(keys + ["ASECWT", "uninsured_ly"])
)
reps = [f"REPWTP{i}" for i in range(1, 161)] # by name, never a REPWTP* wildcard
r = (
pl.scan_parquet("ipums/analysis/cps/cps_asec_repwt/part_2020_2025.parquet")
.filter(pl.col("YEAR") == 2025)
.select(keys + reps)
)
d = p.join(r, on=keys, how="inner").collect()
rep = svy.SdrWgts(prefix="REPWTP", n_reps=160)
s = svy.Sample(d, design=svy.Design(wgt="ASECWT", rep_wgts=rep))
est = s.estimation.mean("uninsured_ly", method="replication", variance_center="estimate", drop_nulls=True)
assert est.to_dicts()[0]["df"] == 159 # the default call would silently report n - 1# Paths point at the book's store; adapt them to your own extract.
library(arrow)
library(dplyr)
library(survey)
keys <- c("YEAR", "SERIAL", "PERNUM")
p <- open_dataset("ipums/analysis/cps/cps_asec/part_2020_2025.parquet") |>
filter(YEAR == 2025) |>
select(all_of(c(keys, "ASECWT", "uninsured_ly"))) |>
collect()
r <- open_dataset("ipums/analysis/cps/cps_asec_repwt/part_2020_2025.parquet") |>
filter(YEAR == 2025) |>
select(all_of(c(keys, paste0("REPWTP", 1:160)))) |>
collect()
d <- inner_join(p, r, by = keys)
des <- svrepdesign(data = d, weights = ~ASECWT, repweights = "^REPWTP[0-9]+$",
type = "successive-difference", mse = TRUE) # scale 4/160, df 159
svymean(~uninsured_ly, des, na.rm = TRUE)* Some CPS replicate weights are negative, so IPUMS declares iweights.
svyset [iweight=asecwt], sdrweight(repwtp1-repwtp160) vce(sdr) dof(159) mse
svy: mean uninsured_lyTwo svy 0.28 behaviors were verified in the build. Once the replication method is requested, svy honors the scale and df arguments of its replicate-weight specification; only the default call ignores the specification, and it ignores all of it. And with method="replication" alone, svy centers the replicate deviations on the mean of the replicates rather than on the full-sample estimate; the Census formula uses the full-sample estimate, which is what variance_center="estimate" and R's mse = TRUE select.
The centering is not a software detail: deviations from the replicate mean and from the full-sample estimate give slightly different variances, and only the second is the producer's.
NHIS 2024
A health economist who needs a national smoking or coverage rate by year, with a standard error a referee will accept, comes to the National Health Interview Survey and asks a question that sounds already answered: the file has STRATA and PSU, so is vce(cluster psu) enough? The NHIS is the principal source on the health of the civilian noninstitutionalized population: coverage, conditions, access, and behaviors such as smoking, reported quarterly. Its trap is in the PSU codes. There are only 108108 codesEstimandDistinct PSU codes in NHIS 2024 (codes are reused across strata)VarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) distinct codes, reused across strata, so a PSU is identified by the pair of stratum and PSU, and code that groups or clusters on the PSU code alone merges areas from different strata without a warning.
The 2024 public file holds 32,62932,629 recordsEstimandSample adult records, NHIS 2024VarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) sample adults and 8,3608,360 recordsEstimandSample child records, NHIS 2024VarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) sample children, each with a weight that sums to the adult or child population. The design has 5252 strataEstimandVariance strata in the NHIS 2024 public fileVarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) strata and 662662 PSUsEstimandDistinct (STRATA, PSU) pairs in the NHIS 2024 public fileVarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) PSUs, so the common rule of PSUs minus strata gives 610610 degrees of freedomEstimandRule-of-thumb design degrees of freedom (PSUs minus strata), NHIS 2024VarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet)NoteNCHS notes the rule of thumb is not directly applicable to the NHIS design. degrees of freedom. NCHS cautions that the rule is not directly applicable to the NHIS design and that it depends on the variable, and says a normal approximation may be adequate when a variable is spread across most clusters (Figure 8.4).
The cost of the PSU trap is measurable. For adult current cigarette smoking, 9.9% (95% CI 9.5%–10.4%)9.9%EstimandShare of US civilian noninstitutionalized adults who currently smoke cigarettes (store flag current_smoker), NHIS 202495% CI9.5%–10.4% (t, df = 610)n31,876WeightSAMPWEIGHTVarianceTaylor linearization (design-based)SourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet)External benchmarkNCHS published 9.9% for 2024 (external benchmark; reproduced in logs/validation_benchmarks_clean.md)NoteDeclared on the whole 2024 file, estimated for sample adults with where=; all PSUs retained., the declared design gives a standard error of 0.2370.237 percentage pointsEstimandTaylor-linearization SE (strata and PSUs) of NHIS 2024 adult current smokingn31,876VarianceTaylor linearization (design-based)SourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) percentage points. A cluster-robust shortcut on the stratum-PSU key gives 0.2620.262 percentage pointsEstimandCRV1 SE of the same weighted mean, clustered on the (STRATA, PSU) key, strata ignoredn31,876VarianceCluster-robust, clustered by psuSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet)Notepyfixest feols(current_smoker ~ 1, weights=SAMPWEIGHT, vcov={'CRV1': psu_key})., 1.11×1.11×EstimandCRV1 (composite PSU key) SE divided by the Taylor SE with strata, NHIS 2024 adult smokingVarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) the design-based standard error, because it ignores the strata and so omits the stratification gain (Appendix B). Clustering on the PSU code alone gives 0.2860.286 percentage pointsEstimandCRV1 SE clustered on the PSU code alone, which merges PSUs from different stratan31,876VarianceCluster-robust, clustered by psuSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet), 1.21×1.21×EstimandCRV1 (PSU code alone) SE divided by the Taylor SE with strataVarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) the design-based figure, and nothing about it looks wrong. svy nests PSU codes within the declared strata on its own, and R's svydesign stops with an error unless told nest = TRUE; both behaviors were confirmed by the build.
NHIS 2024: declared
IPUMS NHIS sample adult and sample child records, Taylor linearization
| Item | Declaration | Provenance |
|---|---|---|
| Pinned release | NHIS 2024 (IPUMS NHIS, YEAR = 2024), fielded under the 2016–2025 sample design | producer: NCHS 2024 survey description |
| Records | 32,629 sample adults and 8,360 sample children | computed from data |
| Universe | Civilian noninstitutionalized population of the United States | producer: NCHS |
| Canonical weight | SAMPWEIGHT; sample-adult/child module weight (module items incl. SMOKESTATUS2, K6); PERWEIGHT for all-person items | design.json |
| Full-population weight rule | PERWEIGHT for 1997-2018 (all-person core items); PERWEIGHT is not released for 2019+ where the public file contains only sample adults + sample children whose SAMPWEIGHT sums to the full civilian noninstitutionalized population — full-population series use PERWEIGHT pre-2019 and SAMPWEIGHT 2019+ | design.json |
| Weight construction | The final annual weight includes design, ratio, nonresponse, and calibration adjustments; calibration controls are age by sex, age by race and ethnicity, education, housing tenure, and region by MSA status | producer: NCHS 2024 survey description |
| Variance method | Taylor linearization (variance_tier: taylor), PSUs treated as sampled with replacement | design.json; producer: NCHS |
| Strata and PSUs | STRATA and PSU (NCHS names PSTRAT and PPSU): 52 strata and 662 PSUs, but only 108 distinct PSU codes, reused across strata | computed from data |
| Composite key | PSU ids repeat across strata: ALWAYS treat (STRATA, PSU) as the clustering key — using PSU alone silently miscomputes variance. | design.json |
| Design df | 610 by the rule PSUs − strata. NCHS notes that the rule is not directly applicable to the NHIS design; a normal approximation may be adequate when a variable is spread across most clusters | computed from data; producer: NCHS |
| Lonely-PSU rule | center (deviations from grand mean, equivalent to R survey option survey.lonely.psu='adjust'); decision recorded per playbook §6 — annual full-file designs have ≥2 PSUs per stratum, singletons can arise only in small domains. Every stratum of the full 2024 file has at least 5 PSUs | design.json; computed from data |
| Zero-weight rows | persons outside the sample-adult/child modules carry SAMPWEIGHT=0 | design.json |
| Pooling rule | Weights: divide each weight by the number of years pooled (NCHS); means and their Taylor SEs are invariant to this uniform rescaling. Variance: years within one NCHS sample design period (with unchanged public-use design variables) re-sample the same PSUs, so the pooled data are treated like one year with a larger sample -- the same (STRATA, PSU) in different years is ONE cluster; treating those years as statistically independent gives standard errors that are too small. Different sample design periods are statistically independent and need distinct strata. IPUMS STRATA embed a design-period indicator and are constant within a period, so pooled views key clusters as design period + STRATA + PSU (pooled_variance_groups). Sources: NCHS, Variance Estimation and Other Analytic Issues in the 1997-2005 NHIS (Nov 2009), pp. 4, 10-12, 15, https://archive.cdc.gov/www_cdc_gov/nchs/data/nhis/9705var.pdf ; NCHS, Variance Estimation Guidance, NHIS 2006-2015 (Jun 2016), pp. 3, 10-12, 15-17, https://archive.cdc.gov/www_cdc_gov/nchs/data/nhis/2006var.pdf ; NCHS, Variance Estimation Guidance, NHIS 2016-2017 (Oct 2018), pp. 1, 3, 8-10, 13, https://archive.cdc.gov/www_cdc_gov/nchs/data/nhis/2016var.pdf ; NCHS, 2019 NHIS Survey Description, pp. 10, 18, 31 (the 2016-2025 sample design continues through the 2019 questionnaire redesign), https://ftp.cdc.gov/pub/Health_Statistics/NCHS/Dataset_Documentation/NHIS/2019/srvydesc-508.pdf ; IPUMS NHIS User Note: Variance Estimation, https://nhis.ipums.org/nhis/userNotes_variance.shtml (verified 2026-09-10). NCHS's 2024 guidance: divide the weight by the number of years pooled and keep PSTRAT and PPSU as they are; 635 of the 662 (STRATA, PSU) pairs of 2024 also appear in 2023 | design.json; producer: NCHS; computed from data |
| Series breaks | 2019: 2019 questionnaire redesign. NHIS content, universes, and weighting redesigned in 2019; NCHS advises caution comparing 2019-forward estimates with earlier years (see nhis_era derived flag). The 2024 sample adds a 25 percent increase in nonmetropolitan households | design.json; producer: NCHS |
| Geography | nation: licensed; region: licensed | design.json |
| Trap: PSU codes | svy nests PSU codes within the declared strata; R's svydesign stops without nest = TRUE; code that groups or clusters on PSU alone merges unrelated PSUs | verified in this build (real data) |
| Last verified | Extended design.json block added 2026-07-11; NCHS and IPUMS documents re-read 2026-09-10 | design.json; this build |
Declare it in Python, R, and Stata
# Paths point at the book's store; adapt them to your own extract.
import polars as pl
import svy
d = pl.read_parquet(
"ipums/analysis/nhis/nhis_core/part_2015_2024.parquet",
columns=["YEAR", "STRATA", "PSU", "SAMPWEIGHT", "ASTATFLG", "current_smoker"],
).filter(pl.col("YEAR") == 2024) # one annual file is one design
d = d.with_columns(pl.col("ASTATFLG").cast(pl.Int64)) # svy 0.28: where= rejects 8- and 16-bit integers
# svy nests PSU codes within strata; hand-rolled code must key on (STRATA, PSU).
s = svy.Sample(d, design=svy.Design(stratum="STRATA", psu="PSU", wgt="SAMPWEIGHT"))
# Sample adults are a domain: declare on the whole file, then estimate with where=.
est = s.estimation.mean("current_smoker", where=svy.col("ASTATFLG") == 1, drop_nulls=True)
print(est.to_dicts()[0]) # df = PSUs - strata# Paths point at the book's store; adapt them to your own extract.
library(arrow)
library(survey)
d <- read_parquet("ipums/analysis/nhis/nhis_core/part_2015_2024.parquet",
col_select = c("YEAR", "STRATA", "PSU", "SAMPWEIGHT", "ASTATFLG", "current_smoker"))
d <- d[d$YEAR == 2024, ]
# PSU codes repeat across strata: nest = TRUE is required (svydesign stops without it).
des <- svydesign(ids = ~PSU, strata = ~STRATA, weights = ~SAMPWEIGHT, nest = TRUE, data = d)
svymean(~current_smoker, subset(des, ASTATFLG == 1), na.rm = TRUE)* NCHS files name these pstrat, ppsu, and wtfa_a; the IPUMS names are shown.
svyset psu [pweight=sampweight], strata(strata) vce(linearized) singleunit(centered)
svy, subpop(if astatflg==1): mean current_smokerThe cast in the Python declaration is a verified trap of its own: svy 0.28 raises an error when a where= condition refers to an 8- or 16-bit integer column, as the IPUMS status flags are stored. The outcome itself may stay narrow.
The smoking estimate is a domain estimate, declared on the whole file and restricted to sample adults; every PSU keeps adults, so it equals the estimate on the adult rows, and the build confirms that it does. Two more rules complete the declaration. Every stratum in the full 2024 file has at least 55 PSUsEstimandFewest PSUs in any stratum of the full NHIS 2024 fileVarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) PSUs, so single-PSU strata arise only in small domains, where the manifest's rule (centering, equivalent to R's adjust) applies and PSUs retained should be reported beside the standard error. And 635635 PSUsEstimand(STRATA, PSU) pairs of NHIS 2024 that also appear in NHIS 2023VarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) of the 2024 PSUs also appear in 2023, because the 2016–2025 design keeps its areas for the decade. NCHS therefore pools years by dividing the weight by the number of years and keeping the stratum and PSU identifiers as they are. Treating each year's PSUs as separate clusters would treat recurring areas as independent.
A field-guide example: adult cigarette smoking, NHIS 2024
- Target population
- Civilian noninstitutionalized adults 18 and older in the United States, 2024.
- Estimand
- The share of those adults who currently smoke cigarettes, as coded by the store's current_smoker flag (from IPUMS SMOKESTATUS2): a finite-population proportion for 2024.
- Estimator
- Hajek weighted proportion over sample adults with a known smoking status, declared on the whole 2024 file and estimated as a domain.
- Explicit weights
- SAMPWEIGHT (NCHS WTFA_A): base weights adjusted for nonresponse and calibrated to age by sex, age by race and ethnicity, education, housing tenure, and region by MSA status.
- Implicit weights
- None beyond the explicit weights: a proportion gives each adult influence in proportion to SAMPWEIGHT.
- Source of randomness
- Sampling of address clusters (PSUs) within strata and of households within clusters, plus response; the weight adjustments are themselves estimated.
- Variance estimator
- Taylor linearization with STRATA and PSU (PSUs nested in strata, treated as sampled with replacement); df by the rule PSUs minus strata. A CRV1 shortcut on the same key omits the stratification gain.
- Assumptions
- The public pseudo-strata and PSUs approximate the confidential design; nonresponse and calibration adjustments remove nonresponse bias; self-reports are accurate. An external benchmark (NCHS's published rate) is a check, not truth.
- Numbers reported
- 9.9%9.9%EstimandShare of US civilian noninstitutionalized adults who currently smoke cigarettes (store flag current_smoker), NHIS 202495% CI9.5%–10.4% (t, df = 610)n31,876WeightSAMPWEIGHTVarianceTaylor linearization (design-based)SourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet)External benchmarkNCHS published 9.9% for 2024 (external benchmark; reproduced in logs/validation_benchmarks_clean.md)NoteDeclared on the whole 2024 file, estimated for sample adults with where=; all PSUs retained.
- 610610 degrees of freedomEstimandRule-of-thumb design degrees of freedom (PSUs minus strata), NHIS 2024VarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet)NoteNCHS notes the rule of thumb is not directly applicable to the NHIS design.degrees of freedom
- 5252 strataEstimandVariance strata in the NHIS 2024 public fileVarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet)strata
- 662662 PSUsEstimandDistinct (STRATA, PSU) pairs in the NHIS 2024 public fileVarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet)PSUs
- 1.11×1.11×EstimandCRV1 (composite PSU key) SE divided by the Taylor SE with strata, NHIS 2024 adult smokingVarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet)
ATUS 2024
A sociologist studying the division of housework, or time with children, or the length of the working day, comes to the American Time Use Survey and asks whether a weighted mean of minutes describes people or days, and whether it can carry a standard error. The ATUS is the country's only continuous record of how people spend their days, and the source of the "how much do Americans work" estimands of Chapter 1. Its trap is the unit. The weight WT06 sums to person-days, not persons, so an average over the weighted file is an average over days, and a standard error computed from the book's extract, which carries no design variables, is not a design-based standard error however carefully it is labeled.
The unit is not a nicety. Weekend diaries are 50.0%50.0%EstimandShare of 2024 ATUS diary days that are a Saturday or Sunday (unweighted)n7,669VarianceNone reportedSourceIPUMS ATUS 2024 (ipums/analysis/atus/atus_respondent.parquet) of the 2024 sample and 28.4%28.4%EstimandShare of 2024 person-days that are a Saturday or Sunday, weighted by WT06n7,669WeightWT06VarianceWeights only: computed without the survey design, so not a design-based standard errorSourceIPUMS ATUS 2024 (ipums/analysis/atus/atus_respondent.parquet) of weighted person-days, so the unweighted mean of minutes worked per diary day is 148.3148.3 minutes per dayEstimandUnweighted mean minutes of working and work-related activities per 2024 ATUS diary dayn7,669VarianceNone reportedSourceIPUMS ATUS 2024 (ipums/analysis/atus/atus_respondent.parquet) and the weighted mean per person-day is 205.5205.5 minutes per dayEstimandMean minutes per person-day of working and work-related activities (BLS_WORK), all 2024 person-days, civilian noninstitutional population 15+, weighted by WT06n7,669WeightWT06VarianceWeights only: computed without the survey design, so not a design-based standard errorSourceIPUMS ATUS 2024 (ipums/analysis/atus/atus_respondent.parquet)NoteNo SE is reported: the extract carries no design variables.. Neither is wrong; they answer different questions, and only the second is the one the sociologist asked. Because the extract carries weights only, the chapter reports no standard error for either.
The survey interviews one person per household, drawn from households that have finished their final CPS interview, about a single designated day; the 2024 file has 7,6697,669 respondentsEstimandRespondents (diary days) in ATUS 2024VarianceNone reportedSourceIPUMS ATUS 2024 (ipums/analysis/atus/atus_respondent.parquet) respondents (Figure 8.5). The design assigns a quarter of the sample to each weekend day and a tenth to each weekday, and the weight returns weekdays to about five-sevenths of person-days. BLS and IPUMS supply 160160 replicate weightsEstimandReplicate final weights BLS and IPUMS provide for each ATUS final weightVarianceNone reportedSourceBLS ATUS user's guide (June 2026); IPUMS ATUS RWT06 replicate weights for each final weight; the variance is 4/1604/160EstimandATUS replicate variance constantVarianceNone reportedSourceBLS ATUS user's guide (June 2026)NoteThe 4 comes from replicate factors 1.7, 1.0, and 0.3. times the sum of squared deviations from the full-sample estimate, the four coming from replicate factors of , , and . The declaration shows both the store's weights-only form and the replicate form to use once the replicate weights are added to the extract.
ATUS 2024: declared
IPUMS ATUS respondent file; the book's extract carries weights only
| Item | Declaration | Provenance |
|---|---|---|
| Pinned release | ATUS 2024 (IPUMS ATUS, YEAR = 2024) | computed from data |
| Records | 7,669 respondents, one diary day each | computed from data |
| Universe | Civilian noninstitutional population age 15 and older; one person per household, drawn from households completing their final CPS interview | producer: BLS ATUS user's guide |
| Unit | diary-day weight: sums to person-DAYS, not persons (2003-2019, 2021+) | design.json |
| Canonical weight | WT06 (BLS: TUFNWGTP on multi-year files, TUFINLWGT on annual files) | design.json; producer: BLS |
| Alternate weights | WT20: REQUIRED for any analysis touching 2020 (COVID collection break; represents Jan1-Mar17 + May10-Dec31 2020 only) | design.json |
| Day sampling | 10 percent of the sample is assigned to each weekday and 25 percent to each weekend day; the weights return weekdays to about 5/7 of person-days | producer: BLS ATUS user's guide |
| Variance in the store | Weights only: no strata, PSUs, or replicate weights in the extract (STRATA is empty), so no design-based SE is possible. No replicate weights in store: weights-only variance understates SEs; BLS publishes replicate weights if needed later. | design.json notes; computed from data |
| Producer replicates | 160 replicate final weights (IPUMS RWT06_1–RWT06_160; BLS FINLWGT001–FINLWGT160); Var = (4/160) × Σ_r (Ŷ_r − Ŷ_0)², the 4 coming from replicate factors 1.7, 1.0, and 0.3 | producer: BLS ATUS user's guide; IPUMS ATUS |
| Design df | Not stated by BLS; the replicate-count convention gives 159 | book guidance |
| Lonely-PSU rule | Not applicable | book guidance |
| Pooling rule | Combine years whose weights were built the same way: WT06 for 2003–2019 and 2021 onward, WT20 for 2020. Do NOT splice WT06/WT20 into one column. | producer: BLS; design.json notes |
| Series breaks | 2020: collection suspended March 18 to May 9, 2020, and WT20 represents only the days covered; the weighting method changed each year from 2003 to 2006 | producer: BLS; design.json |
| Zero-weight rows | 2020 rows have WT06=0 (use WT20); some zero WT06 elsewhere per BLS practice | design.json |
| Trap: person-days | Weights sum to person-days, not persons: an average over days is not an average over people | design.json |
| Trap: unweighted tabulations | Unweighted tabulations overstate activities done more often on weekends | producer: BLS ATUS user's guide |
| Last verified | BLS user's guide (June 2026 edition) and IPUMS RWT06 description read 2026-09-10 | this build |
Declare it in Python, R, and Stata
# Paths point at the book's store; adapt them to your own extract.
import polars as pl
import svy
d = pl.read_parquet(
"ipums/analysis/atus/atus_respondent.parquet",
columns=["YEAR", "WT06", "BLS_WORK"],
).filter(pl.col("YEAR") == 2024)
# No design variables in this extract: the SE treats diary days as a weighted
# with-replacement sample; it is not a design-based SE.
s = svy.Sample(d, design=svy.Design(wgt="WT06"))
est = s.estimation.mean("BLS_WORK")
# With IPUMS RWT06_1-RWT06_160 added to the extract:
# rep = svy.SdrWgts(prefix="RWT06_", n_reps=160)
# s = svy.Sample(d, design=svy.Design(wgt="WT06", rep_wgts=rep))
# est = s.estimation.mean("BLS_WORK", method="replication", variance_center="estimate")# Paths point at the book's store; adapt them to your own extract.
library(arrow)
library(survey)
d <- read_parquet("ipums/analysis/atus/atus_respondent.parquet",
col_select = c("YEAR", "WT06", "BLS_WORK"))
d <- d[d$YEAR == 2024, ]
des <- svydesign(ids = ~1, weights = ~WT06, data = d) # weights only: not a design-based SE
# With RWT06_1-RWT06_160 in the extract:
# des <- svrepdesign(data = d, weights = ~WT06, repweights = "^RWT06_[0-9]+$",
# type = "successive-difference", mse = TRUE)
svymean(~BLS_WORK, des)* Weights only, as in the book's store: the SE is not design-based.
svyset [pweight=wt06]
* With rwt06_1-rwt06_160 in the extract:
* svyset [pweight=wt06], sdrweight(rwt06_1-rwt06_160) vce(sdr) mse
svy: mean bls_workThe 2020 file needs its own weight, WT20, because collection stopped from mid-March to early May; it represents only the days covered, and it must never be spliced into the same column as WT06.
NHANES August 2021–August 2023
An epidemiologist who wants the prevalence of hypertension from measured blood pressure, not from what people report, comes to NHANES and asks which of its several weights to use and how many degrees of freedom a few thousand examinees really carry. NHANES is the one national survey that measures rather than asks: it interviews people at home and then examines them in a mobile center, which is why the hypertension figures of Chapter 3 rest on blood-pressure readings instead of self-report. Its trap is the calendar. Two earlier files overlap, the 2017–2018 cycle and the 2017–March 2020 pre-pandemic file, and they cover the same field period with different participant numbers; an analyst who stacks them to gain sample size counts the same people twice.
The degrees of freedom are the second trap, and they can be priced. Among examined adults, 37.5% (95% CI 35.5%–39.5%)37.5%EstimandShare of examined US civilian noninstitutionalized adults 18+ with hypertension by measured blood pressure (mean reading at or above 130/80 mm Hg) or current medication (store flag htn_measured), NHANES August 2021-August 202395% CI35.5%–39.5% (t, df = 15)n6,123WeightWTMEC2YRVarianceTaylor linearization (design-based)SourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet)NoteDomain of the full design (RIDAGEYR >= 18 and WTMEC2YR > 0); t interval with 15 df. Chapter 3's cascade uses a narrower analytic sample (excludes pregnant women, requires valid readings), so its prevalence differs. have hypertension by measured pressure or medication; the declared design gives a standard error of 0.940.94 percentage pointsEstimandTaylor SE (pseudo-strata and pseudo-PSUs) of the NHANES 2021-2023 measured-hypertension sharen6,123VarianceTaylor linearization (design-based)SourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet) percentage points. Drop the pseudo-strata and pseudo-PSUs and keep the weight, as a regression with robust standard errors would, and the standard error falls to 0.750.75 percentage pointsEstimandSE of the same weighted share with SDMVSTRA and SDMVPSU dropped (weights only, every examinee its own PSU)n6,123VarianceWeights only: computed without the survey design, so not a design-based standard errorSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet)NoteEquals the hand with-replacement formula and R svydesign(ids = ~1).: the design figure is 1.25×1.25×EstimandDesign SE divided by the weights-only SE, NHANES 2021-2023 measured hypertensionVarianceNone reportedSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet) the weights-only one, and the interval also widens because a t with 1515 degrees of freedomEstimandDesign degrees of freedom (PSUs minus strata), NHANES August 2021-August 2023VarianceNone reportedSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet) degrees of freedom replaces the normal (2.132.13Estimand97.5th percentile of t with 15 dfVarianceNone reportedSourcescipy.stats.t in place of 1.961.96Estimand97.5th percentile of the standard normalVarianceNone reportedSourcescipy.stats.norm).
In the August 2021–August 2023 cycle 11,93311,933 participantsEstimandParticipants interviewed, NHANES August 2021-August 2023VarianceNone reportedSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet) people were interviewed and 8,8608,860 participantsEstimandParticipants examined in the mobile examination centerVarianceNone reportedSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet) of them examined, and the two stages have different weights. Examination variables, and laboratory variables measured on every examinee, use the exam weight WTMEC2YR, alone or combined with interview variables; interview-only analyses use WTINT2YR. Analytes measured on a subsample carry their own weights, such as the fasting subsample's WTSAF2YR, and this release adds a phlebotomy weight. NCHS's rule is to use the weight of the smallest subsample whose variables enter the analysis (Figure 8.6 lists the alternates). The public design is masked: 1515 strataEstimandMasked variance pseudo-strata, NHANES August 2021-August 2023VarianceNone reportedSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet) pseudo-strata of two pseudo-PSUs each, 3030 PSUsEstimandMasked variance pseudo-PSUs, NHANES August 2021-August 2023VarianceNone reportedSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet) in all, which leaves 1515 degrees of freedomEstimandDesign degrees of freedom (PSUs minus strata), NHANES August 2021-August 2023VarianceNone reportedSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet) design degrees of freedom however many people are examined.
This cycle is not a continuation of earlier ones. It dropped the oversampling by race, Hispanic origin, and income, selected everyone aged 0 to 19 or 60 and older in a sampled household, used a self-administered screener, and had much lower response rates; NCHS's assessment found no major bias that weighting did not address. Blood pressure has been measured with an oscillometric device since 2017, which reads lower than the earlier auscultatory method.
NHANES August 2021–August 2023: declared
Masked variance units, Taylor linearization
| Item | Declaration | Provenance |
|---|---|---|
| Pinned release | NHANES August 2021–August 2023 (file suffix _L; store CYCLE_YEAR = 2021) | design.json; producer: NCHS |
| Records | 11,933 interviewed, of whom 8,860 were examined; NCHS's DEMO_L counts match | computed from data; producer: NCHS DEMO_L documentation |
| Universe | US civilian noninstitutionalized population, all ages | producer: NCHS |
| Sample design | Multi-year, stratified, clustered four-stage sample with 30 PSUs (counties). No oversampling by race, Hispanic origin, or income this cycle; everyone aged 0–19 or 60 and older encountered in a sampled household was selected | producer: NCHS overview brief |
| Canonical weight | WTMEC2YR for examination and laboratory variables and for any model mixing interview and exam variables; WTINT2YR for interview-only analyses. Not WTMECPRP, which belongs to the 2017–March 2020 file | design.json |
| Alternate weights | Dietary WTDRD1 and WTDR2D; fasting subsample WTSAF2YR; NCHS added a phlebotomy weight in this release to address possible nonresponse bias | design.json; producer: NCHS overview brief |
| Variance method | Taylor linearization (variance_method: taylor). NHANES public releases use Taylor-series linearization with the masked SDMVSTRA/SDMVPSU design variables. No replicate weights are provided. | design.json |
| Strata and PSUs | SDMVSTRA (codes 173–187) and SDMVPSU: 15 masked pseudo-strata and 30 pseudo-PSUs, two per stratum | computed from data; design.json |
| Design df | 15 (PSUs − strata) | computed from data; producer: NHANES tutorial |
| Lonely-PSU rule | SDMVPSU takes values 1-3 nested within each stratum (usually 2 PSUs/stratum). Use survey-package option `singleton='adjust'` (svy) or `options(survey.lonely.psu='adjust')` (R survey) if a domain subset leaves a stratum with one PSU. In svy 0.28 the rule is named "center": s.singleton.handle("center"), which matched R's "adjust" exactly on BRFSS 2024 in this build. | design.json; verified in this build |
| Zero-weight rows | Participants interviewed but not MEC-examined have WTMEC2YR/WTMECPRP = 0 or NA; kept in the file, excluded automatically by weight>0 filters. Do not drop them upstream. | design.json |
| Pooling rule | When pooling k two-year cycles, divide each cycle's 2-year weight by k (NCHS guidance). The 2019 pre-pandemic file spans ~3.2 years and its PRP weights are already scaled to that period; combining it with 2-year cycles requires cycle-appropriate multipliers - consult the NCHS analytic notes before pooling it with individual 2-year cycles. The only NCHS-provided 4-year weights (WTMEC4YR/WTINT4YR) are valid ONLY for 1999-2000 + 2001-2002. | design.json |
| Double count | CYCLE_YEAR==2017 (2017-2018, n=9254) and CYCLE_YEAR==2019 (2017-March 2020 pre-pandemic, n=15560) cover OVERLAPPING field periods - the pre-pandemic file re-includes the 2017-2018 participants under new SEQNs (zero SEQN overlap, invisible to joins). NEVER analyze both together. For 2017-onward coverage use CYCLE_YEAR==2019; for the isolated 2017-2018 cycle use CYCLE_YEAR==2017. | design.json |
| Series breaks | Blood pressure is oscillometric (BPXO) from 2017 and reads lower than the auscultatory BPX used through 2015–2016; a 1.5-year gap separates this cycle from the 2017–March 2020 file; sample design and screener changed | DATA_GUIDE.md; producer: NCHS overview brief |
| Response | Interview response 34.6% and examination response 25.7%, down from 51.0% and 46.9% in 2017–March 2020; NCHS's nonresponse-bias assessment found no major bias not addressed by weighting | producer: NCHS overview brief |
| Geography | National only; the masked variance units are not geography | design.json notes |
| Last verified | design.json generated 2026-07-11; DEMO_L documentation, overview brief, and tutorial read 2026-09-10 | design.json; this build |
Declare it in Python, R, and Stata
# Paths point at the book's store; adapt them to your own extract.
import polars as pl
import svy
d = pl.read_parquet(
"NHANES/data/processed/nhanes_analysis.parquet",
columns=["CYCLE_YEAR", "SDMVSTRA", "SDMVPSU", "WTMEC2YR", "RIDAGEYR", "htn_measured"],
).filter(pl.col("CYCLE_YEAR") == 2021) # August 2021-August 2023 only
s = svy.Sample(d, design=svy.Design(stratum="SDMVSTRA", psu="SDMVPSU", wgt="WTMEC2YR"))
# Examined adults are a domain; interviewed-only participants carry WTMEC2YR = 0.
adults = (svy.col("RIDAGEYR") >= 18) & (svy.col("WTMEC2YR") > 0)
est = s.estimation.mean("htn_measured", where=adults, drop_nulls=True)
print(est.to_dicts()[0]) # df = PSUs - strata# Paths point at the book's store; adapt them to your own extract.
library(arrow)
library(survey)
d <- read_parquet("NHANES/data/processed/nhanes_analysis.parquet",
col_select = c("CYCLE_YEAR", "SDMVSTRA", "SDMVPSU", "WTMEC2YR", "RIDAGEYR", "htn_measured"))
d <- d[d$CYCLE_YEAR == 2021, ]
des <- svydesign(ids = ~SDMVPSU, strata = ~SDMVSTRA, weights = ~WTMEC2YR, nest = TRUE, data = d)
svymean(~htn_measured, subset(des, RIDAGEYR >= 18 & WTMEC2YR > 0), na.rm = TRUE)svyset sdmvpsu [pweight=wtmec2yr], strata(sdmvstra) vce(linearized)
svy, subpop(if ridageyr>=18 & wtmec2yr>0): mean htn_measuredWith so few degrees of freedom, a domain that loses a PSU in any stratum loses a real share of the design. Keep R's default lonely-PSU setting, which stops, so that a collapsed stratum is noticed rather than absorbed.
BRFSS 2024
A health economist evaluating a state policy on self-reported health comes to BRFSS for its state sample sizes and asks two things: can the pooled estimate be called national, and with every respondent a PSU, is there any design left to declare? The Behavioral Risk Factor Surveillance System is a telephone survey run by the states, designed for state-level estimates of health behaviors and conditions, and pooled into the largest health survey in the country. Its trap is the word "national". Tennessee could not collect enough data to meet the minimum requirements in 2024, so an estimate from this file describes adults in participating jurisdictions and should be labeled that way; coverage changes from year to year, since the 2023 file omits Kentucky and Pennsylvania and the 2021 file omits Florida.
The second question has a measured answer, and it is the reverse of NHANES. The share of adults in fair or poor health is 19.6% (95% CI 19.3%–19.8%)19.6%EstimandShare of adults 18+ reporting fair or poor general health, BRFSS 2024 participating jurisdictions (49 states, DC, and three territories; Tennessee absent)95% CI19.3%–19.8% (t, df = 453967)n456,360Weight_LLCPWTVarianceTaylor linearization (design-based)SourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet)NoteStrata _STSTR, PSU _PSU, single-PSU strata centered; df is svy's count on the records with a valid answer., with a design standard error of 0.1340.134 percentage pointsEstimandTaylor SE (strata and PSUs) of the BRFSS 2024 fair-or-poor-health sharen456,360VarianceTaylor linearization (design-based)SourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) percentage points. Drop the strata and PSUs and keep the weight, and the standard error is 0.1350.135 percentage pointsEstimandSE of the same weighted share with _STSTR and _PSU dropped (weights only)n456,360VarianceWeights only: computed without the survey design, so not a design-based standard errorSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet)NoteEquals the hand with-replacement formula and R svydesign(ids = ~1).: the design figure is 1.00×1.00×EstimandDesign SE divided by the weights-only SE, BRFSS 2024 fair or poor healthVarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) the weights-only one, so the strata and PSUs change almost nothing. Drop the weight as well and the point estimate barely moves, to 19.7%19.7%EstimandUnweighted share of BRFSS 2024 respondents with a valid answer who report fair or poor general healthn456,360VarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet), but the standard error of a simple random sample of this size would be 0.0590.059 percentage pointsEstimandSE the weighted share would have as a with-replacement simple random sample of the same size, sqrt(p(1 - p)/n)n456,360VarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet), 2.29×2.29×EstimandDesign SE divided by the simple-random-sample SE (the square root of the design effect), BRFSS 2024 fair or poor healthVarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) too small. For this outcome the weights carry the uncertainty rather than the estimate, and the declaration's strata matter mainly because they stop the software.
The 2024 public file has 457,670457,670 respondentsEstimandRespondent records in the BRFSS 2024 public fileVarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) respondents in 5353 jurisdictionsEstimandJurisdictions in the BRFSS 2024 public file (49 states, DC, and three territories)VarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) jurisdictions: 49 states, the District of Columbia, Guam, Puerto Rico, and the US Virgin Islands. The weight is built in stages: a design weight from the telephone stratum, the adults in the household, and the household's landlines; a compositing adjustment for respondents reachable on both frames; truncation within regions; and raking to state population margins. The book's store keeps only the final weight; Chapter 2 rebuilds the chain from the raw file. The variance design has 2,3932,393 strataEstimandVariance strata (_STSTR), BRFSS 2024VarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) strata and 457,670457,670 PSUsEstimandDistinct (_STSTR, _PSU) pairs, BRFSS 2024VarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) PSUs, one per respondent, which gives 455,277455,277 degrees of freedomEstimandDesign degrees of freedom (PSUs minus strata), BRFSS 2024VarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) design degrees of freedom. BRFSS uncertainty comes from weighting and stratification, not from clustering: the opposite of NHANES (Figure 8.7).
BRFSS 2024: declared
CDC combined landline and cell-phone file; the book's store keeps the final weight
| Item | Declaration | Provenance |
|---|---|---|
| Pinned release | BRFSS 2024 combined landline and cell-phone file (LLCP2024), released August 2025; store: BRFSS_2026 cleaned parquet (iyear = 2024) | producer: CDC; BRFSS_2026 CHANGELOG |
| Records | 457,670 respondents in 53 jurisdictions | computed from data |
| Universe | Noninstitutionalized adults 18 and older in 49 states, DC, Guam, Puerto Rico, and the US Virgin Islands. Tennessee could not collect enough data for the 2024 public file: the target is adults in participating jurisdictions, not US adults | producer: CDC 2024 overview; computed from data |
| Canonical weight | _LLCPWT (store: xllcpwt), the raked final weight | producer: CDC complex sampling weights |
| Alternate weights | _LCPWTV1, _LCPWTV2, _LCPWTV3 for module questions asked on questionnaire versions 1–3 (files LLCP24V1–LLCP24V3); _CLLCPWT for child interviews | producer: CDC complex sampling weights; CDC 2024 weighting description |
| Weight construction | Design weight = _STRWT × (1/NUMPHON4) × NUMADULT (both factors 1 for cell respondents); dual-frame compositing for dual phone users; truncation within region at the mean ± 1.96 SD (_LLCPWT2); raking to 8 state margins plus up to 8 regional and county margins, age by sex last | producer: CDC 2024 weighting description |
| Weights in the store | Only the final xllcpwt; _STRWT, _WT2RAKE, _LLCPWT2, NUMADULT, and NUMPHON4 were dropped by the harmonized build | BRFSS_2026 README; v4 plan |
| Variance method | Taylor linearization with _STSTR (strata) and _PSU (store: xststr, xpsu) | producer: CDC complex sampling weights |
| Strata and PSUs | 2,393 strata and 457,670 PSUs: every respondent is its own PSU (43,913 distinct PSU codes, reused across strata) | computed from data |
| Design df | 455,277 (PSUs − strata) | computed from data |
| Lonely-PSU rule | Required even for national estimates: 110 strata hold a single respondent in the full 2024 file. CDC's R example sets survey.lonely.psu = "adjust"; the book uses "adjust" in R and "center" in svy | computed from data; producer: CDC complex sampling weights |
| Pooling rule | Not covered by the 2024 documents consulted. When pooling years, keep each year's strata distinct and divide weights by the number of years before estimating totals | book guidance |
| Series breaks | Raking and cell phones from 2011 (CDC: begin new trend lines in 2011); coverage changes by year (2021 omits Florida; 2023 omits Kentucky and Pennsylvania; 2024 omits Tennessee); 2020 collection disrupted by COVID; the 2023 file was re-released in February 2025 without sexual orientation and gender identity items, which the 2024 file also omits | producer: CDC; BRFSS_2026 CHANGELOG; v4 plan |
| Geography | Built for state estimates: each state's sample is weighted to its own adult population | producer: CDC 2024 weighting description |
| Trap: self-report | Every measure is self-reported by telephone; weighting repairs representation, not measurement | producer: CDC 2024 overview; book guidance |
| Last verified | CDC 2024 overview, weighting description, and complex-sampling-weights document read 2026-09-10 | this build |
Declare it in Python, R, and Stata
# Paths point at the book's store; adapt them to your own extract.
import polars as pl
import svy
d = (
pl.read_parquet(
"BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet",
columns=["iyear", "xststr", "xpsu", "xllcpwt", "Health"],
)
.filter(pl.col("iyear") == 2024)
.with_columns((pl.col("Health") == "Poor").cast(pl.Float64).alias("fairpoor"))
)
# CDC names: _STSTR, _PSU, _LLCPWT. Every 2024 respondent is its own PSU.
s = svy.Sample(d, design=svy.Design(stratum="xststr", psu="xpsu", wgt="xllcpwt"))
s = s.singleton.handle("center") # single-respondent strata exist even in the full file
est = s.estimation.mean("fairpoor", drop_nulls=True)
print(est.to_dicts()[0])# Paths point at the book's store; adapt them to your own extract.
library(arrow)
library(survey)
d <- read_parquet("BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet",
col_select = c("iyear", "xststr", "xpsu", "xllcpwt", "Health"))
d <- d[d$iyear == 2024, ]
d$fairpoor <- as.numeric(d$Health == "Poor")
options(survey.lonely.psu = "adjust") # CDC's own R example sets this
des <- svydesign(ids = ~xpsu, strata = ~xststr, weights = ~xllcpwt, nest = TRUE, data = d)
svymean(~fairpoor, des, na.rm = TRUE)* CDC names after import sasxport5; the book's store calls them xststr, xpsu, xllcpwt.
svyset _psu [pweight=_llcpwt], strata(_ststr) vce(linearized) singleunit(centered)
svy: mean fairpoorModule questions asked on only some questionnaire versions need the version weights, and states that used more than one version need their weights combined in proportion to sample size, as CDC's module documentation shows. Every measure in BRFSS is self-reported; weighting can repair who is represented, but not how they answered (Chapter 3).
Three worksheets
Each item below is a decision to make and write down; the Analysis Ledger is where the answers go.
Describing a population
- Name the target population and check the release's coverage against it: missing states, group quarters, the institutionalized, the months collected.
- State the unit and the denominator: persons, households, person-days, or examined adults.
- Choose the weight that matches the unit and the source of every variable: person or household, interview or exam, core or module version.
- Declare the whole design first: strata and PSUs, or the replicate weights with their method, constant, and centering.
- Estimate subgroups as domains of the full design, never by deleting rows; report PSUs retained and lonely strata beside the standard error.
- Decide the lonely-PSU rule deliberately and write it down.
- Report the estimate, standard error, design degrees of freedom, unweighted count, and coefficient of variation; suppress cells too small to support an estimate.
- If rates are compared across populations with different age structures, say whether they are crude or standardized, and to which standard.
- Before comparing years, check for series breaks and pooling rules.
- Compare with a published figure where one exists, and label it an external benchmark.
Estimating an effect
- Write the estimand before the regression: a population average effect, the effect on the treated, a population projection coefficient, or a descriptive adjusted contrast.
- Say whether a causal reading is claimed, and if so, under what assumption; otherwise call the contrast descriptive.
- Ask whether selection into the sample depends on the outcome (endogenous sampling). If it does, weights are needed for consistency; if it depends only on the regressors, an unweighted fit of a correctly specified model is consistent, and weighting changes the estimand under heterogeneity rather than rescuing consistency.
- Run the regression weighted and unweighted, and treat a difference as a diagnostic of heterogeneity, misspecification, or endogenous sampling, not a verdict.
- Compute the implicit weights: which cells the coefficient averages over, and how they compare with their population shares.
- Check overlap: list the cells where almost everyone or almost no one is treated.
- If the target is a population average, model the heterogeneity and average the effects over the population distribution.
- Choose the standard errors with the next worksheet.
- Write down what the analysis does not establish.
Choosing standard errors
- Name the repetition the standard error describes: resampling units, reassigning treatment, nonresponse, or a model.
- List every mechanism that induces common uncertainty: survey PSUs within strata, assignment clusters such as states or schools, repeated observations of the same unit.
- If the mechanisms nest, cluster at the coarsest relevant level; if they do not, consider multiway clustering.
- Ask whether the sample holds most of the clusters in the population; if it does, conventional cluster-robust standard errors can be conservative.
- Count the independent units. With few clusters, use the wild cluster bootstrap or a small-sample-corrected variance and t critical values with the right degrees of freedom.
- For survey data, prefer the declared design (Taylor linearization or the producer's replicate weights) to a cluster-robust shortcut, which omits the stratification gain and, keyed on PSU codes alone, can merge unrelated PSUs.
- With replicate weights, use the producer's method, constant, and centering, and assert the degrees of freedom the software reports.
- With weights only, do not present an interval as design-based: its error can run in either direction. Keep to point estimates and estimand lessons, or obtain the design information.
- Report the choice, the assumption behind it, and one alternative as a sensitivity check.
From checklist to methods paragraph
Checklists help a reader recognize the pieces; a methods section has to state them. A paragraph of a familiar kind, invented for illustration:
An example, not quoted from any paper. We analyzed NHANES data with the survey weights to obtain nationally representative estimates, and standard errors accounted for the complex survey design. Hypertension control was compared across periods with t-tests.
Every sentence leaves a decision unstated: which population, definition, weight, design variables, degrees of freedom, denominator, and how many comparisons. The same analysis, written for this book's Chapter 3 result:
Hypertension was defined as a mean of up to three oscillometric readings at or above 130/80 mm Hg, or current use of prescribed blood-pressure medication, following NCHS Data Brief 511. The target population is U.S. civilian noninstitutionalized adults 18 and older, excluding pregnant women, in August 2021–August 2023. Control is the share of adults with hypertension whose readings were below 130/80; it was estimated as a domain of the full design with the examination weight
WTMEC2YR. Standard errors use Taylor linearization with the masked strata and PSUs (SDMVSTRA,SDMVPSU), which leave 1515EstimandDesign degrees of freedom (#PSU - #strata), Aug 2021-Aug 2023VarianceNone reportedSourceNHANES August 2021-August 2023 (_L files), MEC-examined adults; NHANES/data/processed/nhanes_analysis.parquet design degrees of freedom, and intervals use t with those degrees of freedom. Control was 20.7% (95% CI 18.8%–22.7%)20.7% percentEstimandShare with SBP < 130 and DBP < 80 mm Hg, among adults 18+ with hypertension (SBP >= 130 or DBP >= 80 mm Hg, or taking BP medication), Aug 2021-Aug 202395% CI18.8%–22.7% (t, df = 15)n3,242WeightWTMEC2YRVarianceTaylor linearization (design-based)SourceNHANES August 2021-August 2023 (_L files), MEC-examined adults; NHANES/data/processed/nhanes_analysis.parquetExternal benchmarkexternal benchmark: NCHS Data Brief 511 reports 20.7% (95% CI 18.8-22.8), SE 0.9, n = 3,242. Changes from the 2017–March 2020 sample were tested as differences between independent samples with Satterthwaite degrees of freedom; 11EstimandNumber of the 24 period comparisons (4 cascade stages x 6 groups) with p < 0.05 under full-design Taylor (t, Satterthwaite df)VarianceNone reportedSourceNHANES August 2021-August 2023 (_L files), MEC-examined adults; NHANES/data/processed/nhanes_analysis.parquet; NHANES 2017-March 2020 pre-pandemic (P_ files); nhanes_analysis.parquet + nhanes_full_1999_2023.parquet (BPQ040A/BPQ050A) of the 24 period comparisons reached the 5 percent level, about as many as chance alone would produce. The medication question changed between the periods, and the estimates describe measured blood pressure, not diagnosed hypertension.
Each clause fills a field of the Analysis Ledger, and the referee's checklist below asks for the same fields.
The tools: svy, R, and Stata
The same tasks in three languages. The svy column was checked against svy 0.28 on this machine; the R column uses the survey package; the Stata column uses official svy syntax and was not executed.
| Task | Python svy | R survey | Stata |
|---|---|---|---|
| Declare strata and PSUs | svy.Design(stratum="h", psu="psu", wgt="w") | svydesign(ids = ~psu, strata = ~h, weights = ~w, nest = TRUE, data = d) | svyset psu [pweight=w], strata(h) |
| Declare SDR replicate weights | svy.Design(wgt="w", rep_wgts=svy.SdrWgts(prefix="rw", n_reps=80)) | svrepdesign(data = d, weights = ~w, repweights = "^rw[0-9]+$", type = "successive-difference", mse = TRUE) | svyset [pweight=w], sdrweight(rw1-rw80) vce(sdr) mse |
| Estimate on a replicate design | s.estimation.mean("y", method="replication", variance_center="estimate") | svymean(~y, des) | svy: mean y |
| Mean; proportion | s.estimation.mean("y"); s.estimation.prop("y") | svymean(~y, des); svymean(~factor(y), des) | svy: mean y; svy: proportion y |
| Total | s.estimation.total("y") | svytotal(~y, des) | svy: total y |
| Ratio | s.estimation.ratio("y", "x") | svyratio(~y, ~x, des) | svy: ratio y/x |
| Domain estimate | s.estimation.mean("y", where=svy.col("age") >= 65) | svymean(~y, subset(des, age >= 65)) | svy, subpop(if age>=65): mean y |
| Estimates by group | s.estimation.mean("y", by="region") | svyby(~y, ~region, des, svymean) | svy: mean y, over(region) |
| Median | s.estimation.median("y") | svyquantile(~y, des, 0.5) | no official svy command |
| Regression | s.glm.fit("y", x=["x1", "x2"]) | svyglm(y ~ x1 + x2, design = des) | svy: regress y x1 x2 |
| Design effect | s.estimation.mean("y", deff="wr") | svymean(~y, des, deff = "replace") | estat effects after svy: mean y |
| Lonely-PSU rule | s = s.singleton.handle("center") | options(survey.lonely.psu = "adjust") | svyset psu [pweight=w], strata(h) singleunit(centered) |
| Design degrees of freedom | est.to_dicts()[0]["df"] | degf(des) | reported by every svy: command |
| Cluster-robust shortcut | pyfixest.feols("y ~ x", data=d, weights="w", vcov={"CRV1": "psu_key"}) | sandwich::vcovCL(fit, cluster = ~psu_key) | regress y x [pweight=w], vce(cluster psu_key) |
Four behaviors in this table were confirmed by running code: the svy estimation call ignores replicate weights unless the replication method is requested; its where= conditions reject 8- and 16-bit integer columns; R's svydesign stops when PSU codes repeat across strata unless nest = TRUE is set; and R stops on single-PSU strata under its default setting, which is the behavior to keep until the rule is chosen on purpose. The last row is a shortcut, not a declaration: its key must combine stratum and PSU, and even then it ignores the strata. The design-effect row compares with a with-replacement simple random sample in Python and R, the reference this book uses throughout; Stata's estat effects uses its own reference.
A referee's and an advisor's checklist
Ten questions to ask of any survey-based result before it is submitted, each tied to the Ledger field that should already answer it.
| # | Question | Ledger field |
|---|---|---|
| 1 | Whom is the result about, and does the release actually cover them (states, group quarters, months, the institutionalized)? | Target population |
| 2 | What is the estimand, in one sentence, with its unit (persons, households, person-days) and its denominator? | Estimand |
| 3 | What rule produced the number: a weighted mean, a ratio, a standardized rate, a weighted or unweighted regression? | Estimator |
| 4 | Which weight was used, and does it match the unit and the source of every variable (interview or exam, person or household, core or module)? | Explicit weights |
| 5 | Would dropping the weights change the answer, and if so, is that representation, misspecification, or a different estimand? | Explicit weights |
| 6 | With heterogeneous effects, which groups or cells dominate the coefficient, and do they resemble the population? | Implicit weights |
| 7 | Which repetition does the standard error describe: sampling, assignment, nonresponse, or a model? | Source of randomness |
| 8 | Does the variance estimator match the design: strata and PSUs nested correctly, the producer's replicate method and constant, clustering at the level of assignment? What are the degrees of freedom? | Variance estimator |
| 9 | Were subgroups estimated as domains of the full design, how many PSUs and lonely strata remain, and which rule handled them? | Variance estimator |
| 10 | What must hold for the interpretation (coverage, accurate measurement, ignorable nonresponse, a causal assumption), and what does the result not establish? | Assumptions |
Keeping the guides current
A guide is only as current as its "Last verified" row. The guides are rebuilt, not edited: when a producer revises a release or a new one is pinned, the build script regenerates every table and snippet and reruns the checks. The American National Election Studies are the next guide to add.
What we learned about the question
Six releases that are all called complex surveys carry their designs in three different places. The ACS and the CPS ASEC carry theirs entirely in replicate weights, with 7979 degrees of freedomEstimandDesign degrees of freedom for ACS replicate-weight inference (replicates minus 1)VarianceNone reportedSourcedesign.json: ipums/analysis/usa/metadata/acs.design.jsonNote80 replicates - 1, per IPUMS USA repwt FAQ and 159159 degrees of freedomEstimandDesign degrees of freedom for CPS ASEC replicate-weight inferenceVarianceNone reportedSourcedesign.json: ipums/analysis/cps/metadata/cps_asec.design.jsonNote160 replicates - 1, per IPUMS CPS repwt FAQ degrees of freedom fixed by the producer. NHIS, NHANES, and BRFSS carry theirs in strata and PSUs, with 610610 degrees of freedomEstimandRule-of-thumb design degrees of freedom (PSUs minus strata), NHIS 2024VarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet)NoteNCHS notes the rule of thumb is not directly applicable to the NHIS design., 1515 degrees of freedomEstimandDesign degrees of freedom (PSUs minus strata), NHANES August 2021-August 2023VarianceNone reportedSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet), and 455,277455,277 degrees of freedomEstimandDesign degrees of freedom (PSUs minus strata), BRFSS 2024VarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) degrees of freedom: a few dozen counties at one extreme, every respondent a PSU at the other. The book's ATUS extract carries no design at all. Record counts predict none of this.
What the method changed
Running the declarations, rather than reading them, changed three of them. The svy default call ignores declared replicate weights, so the ASEC standard error rose to 1.30×1.30×EstimandReplicate SE divided by the default-call SE, CPS ASEC 2025 uninsured shareVarianceNone reportedSourceIPUMS CPS ASEC 2025 (ipums/analysis/cps/cps_asec and cps_asec_repwt, part_2020_2025) its default value once the replication method was requested. NHIS PSU codes repeat across strata, so nesting is required, and a shortcut clustered on the PSU code alone reports a standard error 1.21×1.21×EstimandCRV1 (PSU code alone) SE divided by the Taylor SE with strataVarianceNone reportedSourceIPUMS NHIS 2024 (ipums/analysis/nhis/nhis_core/part_2015_2024.parquet) the design-based one. BRFSS has 110110 strataEstimandStrata containing a single PSU (one respondent) in the full BRFSS 2024 fileVarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) single-respondent strata in the full file, so a lonely-PSU rule is part of the declaration, not a small-domain afterthought. Pricing the wrong declaration also showed where each survey keeps its uncertainty: in NHANES the strata and PSUs make the standard error 1.25×1.25×EstimandDesign SE divided by the weights-only SE, NHANES 2021-2023 measured hypertensionVarianceNone reportedSourceNHANES August 2021-August 2023 (NHANES/data/processed/nhanes_analysis.parquet) the weights-only figure, while in BRFSS they change it by a factor of 1.00×1.00×EstimandDesign SE divided by the weights-only SE, BRFSS 2024 fair or poor healthVarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet) and the weights alone account for a factor of 2.29×2.29×EstimandDesign SE divided by the simple-random-sample SE (the square root of the design effect), BRFSS 2024 fair or poor healthVarianceNone reportedSourceBRFSS 2024 (BRFSS/BRFSS_2026/cleaned/brfss_multi_rec.parquet).
What this analysis does not establish
- That the Stata declarations run. They follow the producers' published examples and were not executed, because Stata is not installed on the build machine.
- That the ACS declarations behave on the full file. They were checked on a synthetic frame with the same column names, not on the three-gigabyte replicate file.
- Any design-based uncertainty for ATUS. The extract carries weights only; a standard error from it is not design-based and can err in either direction.
- That a correct declaration makes a defensible conclusion. The guides fix the declaration, which is necessary for a defensible standard error and not sufficient; the conclusion still depends on the estimand, the weights the estimator chose, and the repetition the analysis claims to describe.