From 14d7ac17becb357ac3b7a5dfc9af336ab85905fc Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 10 Feb 2026 10:59:40 -0500 Subject: [PATCH] Replace notebook with analysis script for repeal state dependent exemptions - Replace Jupyter notebook with clean Python script mirroring API methodology - Add comprehensive README documenting all neutralized/updated variables - Update state_impacts_detailed.csv with 2026 results using enhanced_cps_2024 Co-Authored-By: Claude Opus 4.6 --- us/state_dependent_exemptions/README.md | 120 ++++++++ .../repeal_state_dependent_exemptions.ipynb | 265 ------------------ .../repeal_state_dependent_exemptions.py | 171 +++++++++++ .../state_impacts_detailed.csv | 79 ++++-- 4 files changed, 344 insertions(+), 291 deletions(-) create mode 100644 us/state_dependent_exemptions/README.md delete mode 100644 us/state_dependent_exemptions/repeal_state_dependent_exemptions.ipynb create mode 100644 us/state_dependent_exemptions/repeal_state_dependent_exemptions.py diff --git a/us/state_dependent_exemptions/README.md b/us/state_dependent_exemptions/README.md new file mode 100644 index 0000000..473b7d3 --- /dev/null +++ b/us/state_dependent_exemptions/README.md @@ -0,0 +1,120 @@ +# Repeal State Dependent Exemptions + +Reform parameter: `gov.contrib.repeal_state_dependent_exemptions.in_effect` + +This reform repeals all state-level dependent exemptions, credits, and deductions that are specifically tied to the number of dependents in a tax unit. Updated formulas replace `tax_unit_size` or `exemptions_count` (which include dependents) with `head_spouse_count` (which excludes them). + +## Microsimulation results + +Dataset: `enhanced_cps_2024` | Period: 2024 + +| Metric | Value | +|---|---| +| Total state tax revenue increase | $5.87B | +| Total household net income decrease | -$5.87B | +| Benefit spending change | $0 | +| Households affected | 20.7M (14.4%) | +| States affected | 34 of 51 | + +Full state-by-state results are in `state_impacts_detailed.csv`. + +### Top 10 states by net income impact + +| State | Net income impact | State tax revenue change | Avg change/HH | % HH affected | +|---|---|---|---|---| +| CA | -$2.43B | +$2.43B | -$163 | 23.1% | +| MI | -$479M | +$479M | -$107 | 24.7% | +| MN | -$433M | +$433M | -$165 | 29.2% | +| IL | -$350M | +$350M | -$60 | 26.9% | +| GA | -$255M | +$255M | -$52 | 20.7% | +| NY | -$245M | +$245M | -$29 | 24.0% | +| SC | -$195M | +$195M | -$82 | 13.4% | +| OH | -$157M | +$157M | -$31 | 23.4% | +| MD | -$140M | +$140M | -$56 | 21.6% | +| NJ | -$117M | +$117M | -$30 | 33.8% | + +## Variables modified by the reform + +### Neutralized variables (set to zero) + +These are dependent-specific variables that are entirely zeroed out. + +| Variable | State | Description | +|---|---|---| +| `al_dependent_exemption` | AL | Alabama dependent exemption | +| `il_dependent_exemption` | IL | Illinois dependent exemption | +| `la_dependents_exemption` | LA | Louisiana dependents exemption | +| `mn_exemptions` | MN | Minnesota exemptions (includes dependents) | +| `ms_dependents_exemption` | MS | Mississippi dependents exemption | +| `nj_dependents_exemption` | NJ | New Jersey dependents exemption | +| `ny_exemptions` | NY | New York exemptions (includes dependents) | +| `sc_dependent_exemption` | SC | South Carolina dependent exemption | +| `ut_personal_exemption` | UT | Utah personal exemption (includes dependents) | +| `nc_child_deduction` | NC | North Carolina child deduction | +| `nm_deduction_for_certain_dependents` | NM | New Mexico deduction for certain dependents | +| `mt_dependent_exemptions_person` | MT | Montana dependent exemptions per person (no effect in 2024; MT eliminated exemptions) | +| `az_dependent_tax_credit` | AZ | Arizona dependent tax credit | +| `ar_personal_credit_dependent` | AR | Arkansas personal credit for dependents | +| `id_ctc` | ID | Idaho child tax credit | +| `me_dependent_exemption_credit` | ME | Maine dependent exemption credit | + +### Updated variables (formula changed to exclude dependents) + +These variables originally used `tax_unit_size`, `exemptions_count`, or `tax_unit_dependents` to include dependents. The reform replaces those with `head_spouse_count` or removes the dependent component. + +| Variable | State | Original pattern | Reform change | +|---|---|---|---| +| `hi_regular_exemptions` | HI | `exemptions_count` (all members) | Uses `head_spouse_count` (head + spouse only) | +| `md_total_personal_exemptions` | MD | `tax_unit_size` (all members) | Uses `head_spouse_count` | +| `mi_personal_exemptions` | MI | `exemptions_count` (all members) | Uses `head_spouse_count` + stillborn children | +| `ne_exemptions` | NE | `exemptions_count` (all members) | Uses `head_spouse_count` | +| `oh_personal_exemptions_eligible_person` | OH | Eligible if head/spouse OR dependent | Eligible only if head/spouse | +| `ok_count_exemptions` | OK | Included dependent exemptions in count | Head + spouse exemptions only | +| `ri_exemptions` | RI | `exemptions_count` (all members) | Uses `head_spouse_count` | +| `vt_personal_exemptions` | VT | Counted dependents in total | Head + spouse only | +| `va_personal_exemption_person` | VA | Applied to all members | Head + spouse only | +| `wv_personal_exemption` | WV | `tax_unit_size` (all members) | Uses `head_spouse_count` | +| `ca_exemptions` | CA | Included dependent credit count | Personal + aged/blind only | +| `ga_exemptions` | GA | `personal + dependent` exemptions | Personal exemptions only | +| `in_base_exemptions` | IN | `exemptions_count` (all members) | Uses `head_spouse_count` | +| `ks_exemptions` | KS | Included dependent amount (2024: `by_filing_status.dependent * dependents`) | Removes dependent amount; keeps base + HOH + veteran amounts | +| `ma_income_tax_exemption_threshold` | MA | Threshold included dependent count | Threshold for head/spouse only | +| `wi_base_exemption` | WI | `exemptions_count` (all members) | Uses `head_spouse_count` | +| `ia_exemption_credit` | IA | Counted dependents in exemption credit | Head/spouse + elderly/blind only | +| `de_personal_credit` | DE | `exemptions_count` (all members) | Uses `head_spouse_count` | +| `ky_family_size_tax_credit_rate` | KY | `tax_unit_size` for poverty index | Uses `head_spouse_count` for poverty index | +| `ok_child_care_child_tax_credit` | OK | Greater of 20% CDCC potential or 5% CTC | 20% of CDCC only (removes CTC component) | + +## Out-of-scope variables + +The following variables reference dependents but are **not** dependent exemptions. They are separate tax programs (credits, rebates, tax rate selection, EITC adjustments) and are intentionally excluded from this reform. + +| Variable | State | Type | Reason excluded | +|---|---|---|---| +| `ct_child_tax_rebate` | CT | Rebate | Per-child cash rebate, not an exemption | +| `ct_property_tax_credit_eligible` | CT | Credit eligibility | Eligibility check (dependents OR elderly) | +| `il_income_tax_rebate` | IL | Rebate | Base + per-dependent rebate amount | +| `ar_low_income_tax_joint` | AR | Tax rate selection | Selects low-income tax table by dependent count | +| `az_family_tax_credit_eligible` | AZ | Credit eligibility | Income limit varies by dependent count | +| `vt_eitc` | VT | EITC adjustment | Match rate varies by child count | +| `ks_fstc` | KS | Food sales tax credit | Credit per exemption for food sales tax | +| `ma_part_b_taxable_income_exemption` | MA | Part B exemption | Includes dependent component but is a broader exemption | +| `ma_scb_total_income` | MA | Income calculation | Re-adds exemptions for Senior Circuit Breaker | +| `hi_disabled_exemptions` | HI | Disabled filer exemption | Dependent exemption only when head/spouse is disabled | +| `wi_homestead_income` | WI | Credit income | Reduces income by dependent exemption for homestead credit | + +## Methodology + +The analysis follows the exact same pattern as the PolicyEngine API (`budget.py` / `compare.py`): + +- `sim.calc()` returns `MicroSeries` with embedded survey weights +- `.sum()` gives weighted population totals (no manual weight multiplication) +- `.count()` gives total household count (sum of weights) +- `household_tax`, `household_state_income_tax`, `household_benefits`, `household_net_income` match the API's tracked variables +- State-level groupby uses `MicroSeries.groupby(state_code).sum()` for weighted aggregation + +## Files + +- `repeal_state_dependent_exemptions.py` - Analysis script +- `state_impacts_detailed.csv` - Full state-by-state results +- `README.md` - This documentation diff --git a/us/state_dependent_exemptions/repeal_state_dependent_exemptions.ipynb b/us/state_dependent_exemptions/repeal_state_dependent_exemptions.ipynb deleted file mode 100644 index f228af5..0000000 --- a/us/state_dependent_exemptions/repeal_state_dependent_exemptions.ipynb +++ /dev/null @@ -1,265 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "from policyengine_us import Microsimulation\n", - "from policyengine_core.reforms import Reform" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "reform = Reform.from_dict(\n", - " {\n", - " \"gov.contrib.repeal_state_dependent_exemptions.in_effect\": {\n", - " \"2024-01-01.2100-12-31\": True\n", - " }\n", - " },\n", - " country_id=\"us\",\n", - ")\n", - "\n", - "\n", - "baseline = Microsimulation(dataset=\"pooled_3_year_cps_2023\")\n", - "reformed = Microsimulation(reform=reform, dataset=\"pooled_3_year_cps_2023\")\n", - "baseline_income = baseline.calculate(\"household_net_income\", period=2024)\n", - "reformed_income = reformed.calculate(\"household_net_income\", period=2024)\n", - "difference_income = reformed_income - baseline_income" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# Get state codes\n", - "state_code = baseline.calculate(\"state_code\", period=2024)\n", - "\n", - "# Get household weights for accurate aggregation\n", - "weights = baseline.calculate(\"household_weight\", period=2024)\n", - "\n", - "# Create a DataFrame with the results\n", - "results_df = pd.DataFrame(\n", - " {\"state_code\": state_code, \"income_change\": difference_income, \"weight\": weights}\n", - ")\n", - "\n", - "# Calculate state-level statistics\n", - "state_impacts = (\n", - " results_df.groupby(\"state_code\")\n", - " .agg(\n", - " {\n", - " \"income_change\": lambda x: np.average(\n", - " x, weights=results_df.loc[x.index, \"weight\"]\n", - " ),\n", - " \"weight\": \"sum\",\n", - " }\n", - " )\n", - " .reset_index()\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "State-by-State Impact Analysis:\n", - " state_code total_households avg_income_change_per_household total_state_income_impact households_affected percent_households_affected\n", - "4 CA 14365824.0 -161.660004 -2.322313e+09 NaN NaN\n", - "22 MI 4228719.0 -113.089996 -4.782457e+08 NaN NaN\n", - "10 GA 4348380.0 -94.570000 -4.112280e+08 NaN NaN\n", - "23 MN 2344873.0 -166.809998 -3.911444e+08 NaN NaN\n", - "14 IL 5187204.0 -61.619999 -3.196205e+08 NaN NaN\n", - "34 NY 7896529.0 -28.510000 -2.251366e+08 NaN NaN\n", - "40 SC 2221951.0 -100.739998 -2.238372e+08 NaN NaN\n", - "31 NJ 3578201.0 -44.169998 -1.580493e+08 NaN NaN\n", - "20 MD 2319566.0 -55.279999 -1.282159e+08 NaN NaN\n", - "35 OH 4992720.0 -23.680000 -1.182335e+08 NaN NaN\n", - "45 VA 3492310.0 -26.049999 -9.097714e+07 NaN NaN\n", - "29 NE 799766.0 -97.879997 -7.828219e+07 NaN NaN\n", - "15 IN 2804274.0 -18.070000 -5.068625e+07 NaN NaN\n", - "36 OK 1626192.0 -23.270000 -3.784758e+07 NaN NaN\n", - "39 RI 463160.0 -79.510002 -3.682365e+07 NaN NaN\n", - "25 MS 1201572.0 -29.100000 -3.496678e+07 NaN NaN\n", - "46 VT 292460.0 -107.150002 -3.133655e+07 NaN NaN\n", - "12 IA 1364209.0 -22.860001 -3.118891e+07 NaN NaN\n", - "49 WV 750805.0 -39.840000 -2.991399e+07 NaN NaN\n", - "1 AL 2120076.0 -12.520000 -2.653426e+07 NaN NaN\n", - "11 HI 500921.0 -46.590000 -2.333804e+07 NaN NaN\n", - "18 LA 1870034.0 -9.250000 -1.730031e+07 NaN NaN\n", - "19 MA 2817993.0 -0.360000 -1.003168e+06 NaN NaN\n", - "16 KS 1215639.0 -0.040000 -4.977200e+04 NaN NaN\n", - "38 PA 5365676.0 0.000000 0.000000e+00 NaN NaN\n", - "42 TN 2986816.0 0.000000 0.000000e+00 NaN NaN\n", - "37 OR 1752219.0 0.000000 0.000000e+00 NaN NaN\n", - "43 TX 11362365.0 0.000000 0.000000e+00 NaN NaN\n", - "44 UT 1150286.0 0.000000 0.000000e+00 NaN NaN\n", - "47 WA 3185000.0 0.000000 0.000000e+00 NaN NaN\n", - "48 WI 2559938.0 0.000000 0.000000e+00 NaN NaN\n", - "41 SD 385189.0 0.000000 0.000000e+00 NaN NaN\n", - "33 NV 1265835.0 0.000000 0.000000e+00 NaN NaN\n", - "0 AK 275571.0 0.000000 0.000000e+00 NaN NaN\n", - "30 NH 591239.0 0.000000 0.000000e+00 NaN NaN\n", - "2 AR 1279007.0 0.000000 0.000000e+00 NaN NaN\n", - "3 AZ 2941938.0 0.000000 0.000000e+00 NaN NaN\n", - "5 CO 2440251.0 0.000000 0.000000e+00 NaN NaN\n", - "6 CT 1503523.0 0.000000 0.000000e+00 NaN NaN\n", - "7 DC 330109.0 0.000000 0.000000e+00 NaN NaN\n", - "8 DE 410404.0 0.000000 0.000000e+00 NaN NaN\n", - "32 NM 882902.0 0.000000 0.000000e+00 NaN NaN\n", - "9 FL 9323535.0 0.000000 0.000000e+00 NaN NaN\n", - "17 KY 1886632.0 0.000000 0.000000e+00 NaN NaN\n", - "21 ME 608698.0 0.000000 0.000000e+00 NaN NaN\n", - "24 MO 2570655.0 0.000000 0.000000e+00 NaN NaN\n", - "26 MT 494750.0 0.000000 0.000000e+00 NaN NaN\n", - "27 NC 4553814.0 0.000000 0.000000e+00 NaN NaN\n", - "28 ND 338181.0 0.000000 0.000000e+00 NaN NaN\n", - "13 ID 769370.0 0.000000 0.000000e+00 NaN NaN\n", - "50 WY 242744.0 0.000000 0.000000e+00 NaN NaN\n", - "0 TOTAL 134260032.0 -39.224422 -5.266272e+09 0.0 0.0\n" - ] - } - ], - "source": [ - "# Calculate total income impact\n", - "total_impact_by_state = (\n", - " results_df.groupby(\"state_code\")\n", - " .apply(lambda x: np.sum(x[\"income_change\"] * x[\"weight\"]))\n", - " .reset_index(name=\"total_income_impact\")\n", - ")\n", - "\n", - "# Merge total impact into main results\n", - "state_impacts = state_impacts.merge(total_impact_by_state, on=\"state_code\")\n", - "\n", - "# Add households affected\n", - "state_impacts[\"households_affected\"] = (\n", - " results_df[results_df[\"income_change\"] != 0]\n", - " .groupby(\"state_code\")[\"weight\"]\n", - " .sum()\n", - " .reindex(state_impacts[\"state_code\"])\n", - " .fillna(0)\n", - ")\n", - "\n", - "# Calculate percentage of households affected\n", - "state_impacts[\"percent_households_affected\"] = (\n", - " state_impacts[\"households_affected\"] / state_impacts[\"weight\"] * 100\n", - ")\n", - "\n", - "# Format the results\n", - "state_impacts[\"avg_income_change\"] = state_impacts[\"income_change\"].round(2)\n", - "state_impacts[\"total_income_impact\"] = state_impacts[\"total_income_impact\"].round(0)\n", - "state_impacts[\"households_affected\"] = state_impacts[\"households_affected\"].round(0)\n", - "state_impacts[\"percent_households_affected\"] = state_impacts[\n", - " \"percent_households_affected\"\n", - "].round(2)\n", - "state_impacts[\"weight\"] = state_impacts[\"weight\"].round(0)\n", - "\n", - "# Sort by total impact\n", - "state_impacts_sorted = state_impacts.sort_values(\"total_income_impact\")\n", - "\n", - "# Rename columns for clarity\n", - "state_impacts_sorted = state_impacts_sorted.rename(\n", - " columns={\n", - " \"weight\": \"total_households\",\n", - " \"avg_income_change\": \"avg_income_change_per_household\",\n", - " \"total_income_impact\": \"total_state_income_impact\",\n", - " }\n", - ")\n", - "\n", - "# Calculate national totals\n", - "national_totals = pd.DataFrame(\n", - " {\n", - " \"state_code\": [\"TOTAL\"],\n", - " \"total_households\": [state_impacts_sorted[\"total_households\"].sum()],\n", - " \"avg_income_change_per_household\": [\n", - " (\n", - " state_impacts_sorted[\"total_state_income_impact\"].sum()\n", - " / state_impacts_sorted[\"total_households\"].sum()\n", - " )\n", - " ],\n", - " \"total_state_income_impact\": [\n", - " state_impacts_sorted[\"total_state_income_impact\"].sum()\n", - " ],\n", - " \"households_affected\": [state_impacts_sorted[\"households_affected\"].sum()],\n", - " \"percent_households_affected\": [\n", - " (\n", - " state_impacts_sorted[\"households_affected\"].sum()\n", - " / state_impacts_sorted[\"total_households\"].sum()\n", - " * 100\n", - " )\n", - " ],\n", - " }\n", - ")\n", - "\n", - "# Combine state results with national totals\n", - "final_results = pd.concat([state_impacts_sorted, national_totals])\n", - "\n", - "# Display results\n", - "print(\"\\nState-by-State Impact Analysis:\")\n", - "print(\n", - " final_results[\n", - " [\n", - " \"state_code\",\n", - " \"total_households\",\n", - " \"avg_income_change_per_household\",\n", - " \"total_state_income_impact\",\n", - " \"households_affected\",\n", - " \"percent_households_affected\",\n", - " ]\n", - " ].to_string()\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "final_results.to_csv(\"state_impacts_detailed.csv\", index=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "pe", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.14" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/us/state_dependent_exemptions/repeal_state_dependent_exemptions.py b/us/state_dependent_exemptions/repeal_state_dependent_exemptions.py new file mode 100644 index 0000000..bd5e79f --- /dev/null +++ b/us/state_dependent_exemptions/repeal_state_dependent_exemptions.py @@ -0,0 +1,171 @@ +""" +Repeal State Dependent Exemptions - State Impact Analysis + +Uses the same methodology as the PolicyEngine API (budget.py / compare.py). +sim.calc() returns MicroSeries with embedded weights, so .sum() gives +the weighted population total without manual weight multiplication. +""" + +import os + +import pandas as pd +from microdf import MicroSeries +from policyengine_core.reforms import Reform +from policyengine_us import Microsimulation + +PERIOD = 2026 + +REFORM_PARAM = ( + "gov.contrib.repeal_state_dependent_exemptions.in_effect" +) + + +def calc_change(baseline, reformed, variable, period, **kwargs): + """Return (baseline, reformed, change) MicroSeries for a variable.""" + b = baseline.calc(variable, period=period, **kwargs) + r = reformed.calc(variable, period=period, **kwargs) + return b, r, r - b + + +def run_analysis(): + reform = Reform.from_dict( + {REFORM_PARAM: {"2024-01-01.2100-12-31": True}}, + country_id="us", + ) + baseline = Microsimulation() + reformed = Microsimulation(reform=reform) + + # --- Household-level changes (reused for national + state) --- + _, _, hh_income_change = calc_change( + baseline, reformed, "household_net_income", PERIOD + ) + _, _, hh_tax_change = calc_change( + baseline, reformed, "household_tax", PERIOD + ) + _, _, hh_state_tax_change = calc_change( + baseline, reformed, + "household_state_income_tax", PERIOD, + map_to="household", + ) + _, _, hh_benefits_change = calc_change( + baseline, reformed, "household_benefits", PERIOD + ) + + # --- National totals --- + total_households = hh_income_change.count() + net_income_impact = hh_income_change.sum() + tax_revenue_impact = hh_tax_change.sum() + state_tax_revenue_impact = hh_state_tax_change.sum() + benefit_spending_impact = hh_benefits_change.sum() + budgetary_impact = tax_revenue_impact - benefit_spending_impact + + print(f"\n=== Repeal State Dependent Exemptions ===") + print(f"Dataset: enhanced_cps_2024 | Period: {PERIOD}") + print(f"Reform: {REFORM_PARAM}") + print(f"Total households: {total_households:,.0f}\n") + print("National Budgetary Impact (API pattern):") + for label, value in [ + ("Tax revenue impact", tax_revenue_impact), + ("State tax revenue impact", state_tax_revenue_impact), + ("Benefit spending impact", benefit_spending_impact), + ("Budgetary impact", budgetary_impact), + ("Net income impact", net_income_impact), + ]: + print(f" {label + ':':<28s}${value:>15,.0f}") + + # --- State-level groupby --- + state_code = baseline.calc("state_code", period=PERIOD) + household_weight = baseline.calc( + "household_weight", period=PERIOD + ) + + by_state = { + "income_change": hh_income_change.groupby(state_code), + "state_tax_change": hh_state_tax_change.groupby( + state_code + ), + } + + affected = MicroSeries( + (hh_income_change.abs() > 0.01).astype(float).values, + weights=household_weight.values, + ) + + income_sum = by_state["income_change"].sum() + income_mean = by_state["income_change"].mean() + income_count = by_state["income_change"].count() + tax_sum = by_state["state_tax_change"].sum() + affected_sum = affected.groupby(state_code).sum() + + # --- Build results table --- + state_results = [] + for state in income_sum.index: + total_hh = income_count[state] + affected_hh = affected_sum[state] + state_results.append({ + "state_code": state, + "total_households": round(total_hh), + "avg_net_income_change": round(income_mean[state], 2), + "total_net_income_impact": round(income_sum[state]), + "total_state_tax_revenue_change": round(tax_sum[state]), + "households_affected": round(affected_hh), + "pct_households_affected": ( + round(affected_hh / total_hh * 100, 2) + if total_hh > 0 + else 0 + ), + }) + + state_impacts = pd.DataFrame(state_results).sort_values( + "total_net_income_impact" + ) + + total_affected = state_impacts["households_affected"].sum() + national = pd.DataFrame([{ + "state_code": "TOTAL", + "total_households": round(total_households), + "avg_net_income_change": round( + net_income_impact / total_households, 2 + ), + "total_net_income_impact": round(net_income_impact), + "total_state_tax_revenue_change": round( + state_tax_revenue_impact + ), + "households_affected": total_affected, + "pct_households_affected": round( + total_affected / total_households * 100, 2 + ), + }]) + + final = pd.concat( + [state_impacts, national], ignore_index=True + ) + + # --- Print state results --- + print("\nState-by-State Impact Analysis:") + print(final.to_string(index=False)) + + affected_states = state_impacts[ + state_impacts["total_net_income_impact"] != 0 + ] + + print(f"\n\nAffected states: {len(affected_states)}") + print(f"Total budgetary impact: ${budgetary_impact:,.0f}") + print( + f"Total state tax revenue change: " + f"${state_tax_revenue_impact:,.0f}" + ) + + # --- Save CSV --- + script_dir = os.path.dirname(os.path.abspath(__file__)) + output_path = os.path.join( + script_dir, "state_impacts_detailed.csv" + ) + final.to_csv(output_path, index=False) + print(f"\nResults saved to {output_path}") + + return final + + +if __name__ == "__main__": + results = run_analysis() diff --git a/us/state_dependent_exemptions/state_impacts_detailed.csv b/us/state_dependent_exemptions/state_impacts_detailed.csv index d25815e..afad600 100644 --- a/us/state_dependent_exemptions/state_impacts_detailed.csv +++ b/us/state_dependent_exemptions/state_impacts_detailed.csv @@ -1,26 +1,53 @@ -state_code,income_change,total_households,total_state_income_impact,households_affected,percent_households_affected,avg_income_change_per_household -CA,-161.65538,14365824.0,-2322312700.0,,,-161.66 -MI,-113.0947,4228719.0,-478245730.0,,,-113.09 -GA,-94.5704,4348380.0,-411227970.0,,,-94.57 -MN,-166.80835,2344873.0,-391144400.0,,,-166.81 -IL,-61.617107,5187204.0,-319620480.0,,,-61.62 -NY,-28.510832,7896529.0,-225136600.0,,,-28.51 -SC,-100.73903,2221951.0,-223837170.0,,,-100.74 -NJ,-44.170063,3578201.0,-158049340.0,,,-44.17 -MD,-55.2758,2319566.0,-128215890.0,,,-55.28 -OH,-23.681173,4992720.0,-118233464.0,,,-23.68 -VA,-26.05071,3492310.0,-90977144.0,,,-26.05 -NE,-97.881355,799766.0,-78282190.0,,,-97.88 -IN,-18.07464,2804274.0,-50686250.0,,,-18.07 -OK,-23.273746,1626192.0,-37847576.0,,,-23.27 -RI,-79.50533,463160.0,-36823652.0,,,-79.51 -MS,-29.100868,1201572.0,-34966784.0,,,-29.1 -VT,-107.14814,292460.0,-31336546.0,,,-107.15 -IA,-22.862263,1364209.0,-31188908.0,,,-22.86 -WV,-39.842545,750805.0,-29913988.0,,,-39.84 -AL,-12.515711,2120076.0,-26534264.0,,,-12.52 -HI,-46.590252,500921.0,-23338042.0,,,-46.59 -LA,-9.251335,1870034.0,-17300312.0,,,-9.25 -MA,-0.35598665,2817993.0,-1003168.0,,,-0.36 -KS,-0.040942732,1215639.0,-49772.0,,,-0.04 -TOTAL,,134260030.0,-5266272000.0,0.0,0.0,-39.224422 +state_code,total_households,avg_net_income_change,total_net_income_impact,total_state_tax_revenue_change,households_affected,pct_households_affected +CA,15127167,-169.35,-2561827617,2561820868,3513198,23.22 +MI,4558849,-116.26,-529989526,529989449,1135239,24.9 +IL,5885320,-64.14,-377479507,377480178,1617979,27.49 +MN,2670094,-119.85,-320006428,320008319,579964,21.72 +GA,4981452,-55.69,-277418504,277420722,1089351,21.87 +NY,8552348,-25.96,-222047438,222047440,2193229,25.64 +SC,2425942,-84.77,-205647853,205648353,332913,13.72 +MD,2551392,-64.22,-163860241,163860279,519238,20.35 +NJ,3969209,-33.18,-131678672,131677488,1343612,33.85 +OH,5060310,-25.13,-127186821,127186565,1127384,22.28 +AZ,2969877,-31.21,-92682828,92682751,625628,21.07 +UT,1160493,-79.61,-92391599,92391508,256170,22.07 +VA,3429402,-26.32,-90244896,90244882,979128,28.55 +KS,1166768,-75.67,-88287314,88286815,413591,35.45 +ME,647656,-134.69,-87234481,87234481,123553,19.08 +NE,861520,-87.38,-75275375,75275475,245551,28.5 +OK,1847273,-38.85,-71762104,71762098,460049,24.9 +IN,2916853,-16.21,-47268228,47268125,1001955,34.35 +WI,3035830,-12.75,-38720367,38721620,464113,15.29 +NC,5185583,-6.6,-34209760,34210783,404400,7.8 +KY,1843720,-18.3,-33746851,33746738,81023,4.39 +VT,289740,-112.15,-32494052,32494066,62554,21.59 +RI,471881,-65.26,-30794782,30794817,100315,21.26 +AL,2342898,-12.64,-29615116,29615169,560061,23.9 +WV,778857,-34.28,-26696525,26696080,189194,24.29 +NM,1107251,-23.94,-26508429,26508430,120502,10.88 +IA,1474272,-17.88,-26357814,26357810,307530,20.86 +MS,1414641,-14.98,-21191976,21191941,232293,16.42 +HI,503327,-41.31,-20793686,20793704,149239,29.65 +DE,462807,-42.19,-19526227,19526222,143434,30.99 +AR,1303564,-11.18,-14577410,14577410,287623,22.06 +MA,2973032,-0.05,-145907,145905,2297,0.08 +TN,3273205,0.0,0,0,0,0.0 +WA,3279983,0.0,0,0,0,0.0 +PA,5666221,0.0,0,0,0,0.0 +SD,386216,0.0,0,0,0,0.0 +TX,13074578,0.0,0,0,0,0.0 +AK,298739,0.0,0,0,0,0.0 +NV,1308034,0.0,0,0,0,0.0 +NH,623165,0.0,0,0,0,0.0 +ND,336307,0.0,0,0,0,0.0 +MT,491800,0.0,0,0,0,0.0 +MO,2630014,0.0,0,0,0,0.0 +LA,2216062,0.0,0,0,0,0.0 +ID,806453,0.0,0,0,0,0.0 +FL,11090333,0.0,0,0,0,0.0 +DC,442905,0.0,0,0,0,0.0 +CT,1589977,0.0,0,0,0,0.0 +CO,2609908,0.0,0,0,0,0.0 +OR,1902614,0.0,0,0,0,0.0 +WY,255575,0.0,0,0,0,0.0 +TOTAL,146251418,-40.46,-5917668334,5917666492,20662310,14.13