-
Notifications
You must be signed in to change notification settings - Fork 34
Description
Bug
The intra_decile_impact and intra_wealth_decile_impact functions in policyengine_api/endpoints/economy/compare.py (lines 324-331, 386-393) double all household percentage income changes due to a variable name error.
The code (line 326-331)
absolute_change = (reform_income - baseline_income).values
capped_baseline_income = np.maximum(baseline_income.values, 1)
capped_reform_income = (
np.maximum(reform_income.values, 1) + absolute_change # <-- bug: reform_income should be baseline_income
)
income_change = (
capped_reform_income - capped_baseline_income
) / capped_baseline_incomeWhy it's wrong
For the common case (both baseline and reform income >= 1):
absolute_change = R - B
capped_baseline = B
capped_reform = R + (R - B) = 2R - B
income_change = (2R - B - B) / B = 2(R - B) / B
That's 2x the actual percentage change. A household going from $50,000 to $52,500 (5% gain) registers as 10%.
The fix
Line 327 should use baseline_income.values instead of reform_income.values:
capped_reform_income = (
np.maximum(baseline_income.values, 1) + absolute_change
)This gives (R - B) / max(B, 1) — the standard percentage change with a floor of 1 to avoid division by zero. Same fix needed on line 389 for intra_wealth_decile_impact.
Or more simply, replace lines 324-331 with:
absolute_change = (reform_income - baseline_income).values
capped_baseline_income = np.maximum(baseline_income.values, 1)
income_change = absolute_change / capped_baseline_incomeOrigin
Introduced in commit 20292bf7 (Dec 28, 2022, PR #38, branch intra-decile-fix). The commit was titled "Fix bug in intra-decile chart" and was addressing negative income edge cases. The original formula np.maximum(reform_income, 1) / np.maximum(baseline_income, 1) - 1 was correct for the common case but mishandled households where both incomes were below 1. The rewrite accidentally used reform_income where it meant baseline_income.
Impact
- All intra-decile winners/losers charts on policyengine.org overstate the proportion of people with large gains or losses (>5%) and understate small changes (<5%) and "No change"
- Affects both income decile and wealth decile breakdowns
- The same formula was copied into
PolicyEngine/state-legislative-tracker(scripts/compute_impacts.py) - Not visually obvious because proportions still sum to 100% — reforms just appear more dramatic than they are
Note for v2 API
This calculation has not yet been ported to policyengine-api-v2. When porting, use the corrected formula.