Skip to content

Extrapolate post-2022 weights using a CBO returns (not a CBO population) projection - #546

Merged
martinholmer merged 6 commits into
masterfrom
revise-weights-projection
Sep 9, 2026
Merged

martinholmer merged 6 commits into
masterfrom
revise-weights-projection

Conversation

@martinholmer

@martinholmer martinholmer commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator

Walkthrough of PR 546

Commits 1c02462 .. 8b895f3, six commits in all, relative to origin/master
(a442830). The headline change is how post-TAXYEAR sampling weights are
extrapolated
; the rest of the PR is pipeline ordering, path constants, and
documentation cleanup.

1. Grow weights with CBO's tax-return projection (1c02462)

Previously the TAXYEAR (2022) weights were scaled forward by CBO's total
population
growth, which implicitly holds returns-per-capita fixed. CBO
projects the number of returns growing about twice as fast as population
(+11.9% vs +5.9% over 2022-2036) because the filing share keeps rising, so
population growth pushed aggregate AGI and income tax revenue progressively
below CBO's projections.

Changes:

  • New input file tmd/storage/input/cbo26_returns.yaml — CBO's projected
    number of individual income tax returns (161.3M in 2022 rising to 180.5M in
    2036), taken from the same workbook/sheet/row that supplies n_returns_mil
    in tests/expected_cbo_levels_2022_data.yaml.
  • New module tmd/utils/weight_growth.py with cumulative_growth(first_year, last_year): year-over-year return growth through the last projected return
    year (2036, the end of the CBO budget window), then population growth
    thereafter (which holds returns-per-capita fixed at its final projected
    value) out to the last weight year.
  • tmd/imputation_assumptions.py adds RET_FILE / RETURNS_FILE, keyed by
    TAXYEAR. RETURNS_FILE = None (as for TAXYEAR 2021) falls back to
    population growth in every year, so the old behavior is still reachable.
  • tmd/create_taxcalc_sampling_weights.py and
    tmd/areas/create_area_weights.py both now call cumulative_growth, so
    national and sub-national weights are extrapolated identically.
  • New test tests/test_weight_growth.py (96 lines) checks the growth
    dictionary covers all weight years, anchors at 1.0 in TAXYEAR, and tracks
    the return projection through its last year.

2022 weights are unchanged (fingerprints hold); every post-2022 weight is
larger. Expected-value files move accordingly:
tests/expected_tax_exp_2022_data rises ~1% across the board (e.g. 2023
iitax 2332.3 -> 2357.2, paytax 1431.0 -> 1446.3), and the four
exp_totben_2022 values in tests/test_imputed_variables.py rise ~1-2%.

2. tests/expect_tmd_revenues: branch vs master

This is the clearest evidence of the improvement. TMD's ACTUAL aggregate
income tax revenue moves up toward CBO's EXPECT, while the calibrated 2022
anchor is untouched.

Year ACTUAL (master) ACTUAL (branch) PCTDIFF (master) PCTDIFF (branch)
2022 2149.4 2149.4 -0.01 -0.01
2023 2218.1 2241.8 +2.13 +3.22
2024 2407.9 2441.3 -0.02 +1.36
2025 2491.9 2520.3 -0.07 +1.07
2026 2637.4 2685.1 -1.04 +0.75
2027 2697.5 2760.4 -2.85 -0.59
2028 2757.4 2835.8 -3.59 -0.85
2029 2898.3 2991.6 -4.63 -1.56
2030 3049.1 3158.0 -4.62 -1.21
2031 3171.2 3302.8 -4.20 -0.22
2032 3302.1 3451.1 -4.35 -0.03
2033 3438.6 3604.9 -4.47 +0.15
2034 3581.8 3765.1 -4.75 +0.12
2035 3730.6 3932.5 -5.06 +0.08

Sum over 2022-2035 of squared PCTDIFF for iitax falls from 174.05 to
19.00
. The EXPECT (CBO) column is unchanged. On master the shortfall
grows monotonically to -5.06% by 2035; on the branch every year from 2027
on is within about 1.6%, and 2031-2035 within 0.2%. The one remaining
outlier, 2023 (+3.22%, up from +2.13%), is a known level discrepancy in the
2023 comparison rather than a drift.

3. Build the growth-factors files first (963f56a)

Makefile now expresses real dependencies for the tmd_files pipeline:
growfactors.csv -> tmd_growfactors.csv -> tmd.csv.gz ->
tmd_weights.csv.gz. Previously the input-variables and weights stages ran
before the growth-factors stage, even though later stages need
growfactors.csv as the Policy-parameter indexing file and
tmd_growfactors.csv as the Records-variable extrapolation file.

Consistent with that, every place that built a taxcalc.Policy() with the
library's built-in growth factors now passes the project's own
growfactors.csv: tmd/create_taxcalc_cached_files.py,
tmd/datasets/cps.py, tmd/utils/soi_replication.py, and
tmd/utils/taxcalc_output.py.

4. Centralize output paths (5dd5776)

tmd/storage/__init__.py gains POLICY_GROWFACTORS_PATH,
TMD_VARIABLES_PATH, TMD_WEIGHTS_PATH, and TMD_GROWFACTORS_PATH. The
four path-only pytest fixtures in tests/conftest.py
(tmd_variables_path, tmd_weights_path, tmd_growfactors_path,
policy_growfactors_path) are deleted, and the six tests that used them
import the constants directly instead. Net effect: fewer fixtures, shorter
test signatures, one place where output paths are defined.

5. Narrow the CBO revenue-level tolerances (9a3ad99)

tests/test_revenue_levels_cbo.py tightens RELTOL for n_returns_mil,
agi_bil, and iitax_bil from 2%/5%/6% in 2026/2031/2036 to a flat 1%
in every checked year — a tolerance that only passes because of the change in
section 1.

6. Area-weight plumbing and docs (348b7f3, 8b895f3)

  • tmd/areas/batch_weights.py and tmd/areas/sweep_params.py drop the
    now-unneeded _WORKER_POP / _POP preloaded population dictionary and the
    POPFILE_PATH import, calling cumulative_growth instead.
  • batch_weights.py's staleness check adds tmd/utils/weight_growth.py and
    the returns YAML file (when one is configured) to its dependency list, so
    area weights rebuild when the projection changes.
  • README.md declares TMD version 2.2.0 (released 2026-09-09): identical
    to 2.1.4 except for the returns-based weight projection; 2022 weights and
    fingerprints unchanged, all post-2022 weights larger. The older 2.0.0
    release-notes block is removed. 118th CD fingerprints remain un-updated.

Scope summary

16 files differ from origin/master at the branch tip (+132/-146), plus the
files introduced and then unchanged since 1c02462
(cbo26_returns.yaml, weight_growth.py, test_weight_growth.py,
expect_tmd_revenues, expected_tax_exp_2022_data). No changes to the
imputation or reweighting algorithms themselves — only to how the solved
TAXYEAR weights are carried forward, and to build ordering and test plumbing.

@martinholmer
martinholmer marked this pull request as draft September 8, 2026 23:25
@martinholmer martinholmer changed the title Revise weights projection Grow weights using CBO returns (not CBO population) projection Sep 8, 2026
@martinholmer martinholmer changed the title Grow weights using CBO returns (not CBO population) projection Grow post-2022 weights using CBO returns (not CBO population) projection Sep 9, 2026
@martinholmer martinholmer changed the title Grow post-2022 weights using CBO returns (not CBO population) projection Grow post-2022 weights using a CBO returns (not a CBO population) projection Sep 9, 2026
@martinholmer
martinholmer marked this pull request as ready for review September 9, 2026 20:32
@martinholmer martinholmer changed the title Grow post-2022 weights using a CBO returns (not a CBO population) projection Extrapolate post-2022 weights using a CBO returns (not a CBO population) projection Sep 9, 2026
@martinholmer
martinholmer merged commit 282f176 into master Sep 9, 2026
1 check passed
@martinholmer
martinholmer deleted the revise-weights-projection branch September 9, 2026 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant