Created
July 25, 2025 23:50
-
-
Save MaxGhenis/1e4543a64ad1c14b4ef1858e29babdb1 to your computer and use it in GitHub Desktop.
Complete analysis of household 4428 itemization
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Household 4428 Itemization Analysis\n", | |
| "\n", | |
| "This notebook clarifies the itemization behavior and apparent calculation issues." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "from policyengine_us import Microsimulation\n", | |
| "from policyengine_us.model_api import *\n", | |
| "import numpy as np\n", | |
| "\n", | |
| "# Setup\n", | |
| "DATASET = \"hf://policyengine/policyengine-us-data/enhanced_cps_2024.h5\"\n", | |
| "YEAR = 2026\n", | |
| "\n", | |
| "# Reform stack\n", | |
| "reform = Reform.from_dict({\n", | |
| " \"gov.irs.income.bracket.rates.2\": {\"2026-01-01\": 0.15},\n", | |
| " \"gov.irs.income.bracket.rates.3\": {\"2026-01-01\": 0.25},\n", | |
| " \"gov.irs.deductions.standard.amount.JOINT\": {\"2026-01-01\": 48900},\n", | |
| " \"gov.irs.income.exemption.amount\": {\"2026-01-01\": 0},\n", | |
| " \"gov.contrib.reconciliation.ctc.in_effect\": {\"2026-01-01\": True},\n", | |
| " \"gov.irs.credits.ctc.amount.base[0].amount\": {\"2026-01-01\": 2200},\n", | |
| "}, country_id=\"us\")\n", | |
| "\n", | |
| "sim = Microsimulation(reform=reform, dataset=DATASET)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "## Key Finding: Household 4428 Has Two Tax Units" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Get data for both tax units\n", | |
| "tax_unit_ids = sim.calculate(\"tax_unit_id\", period=YEAR).values\n", | |
| "tu1_idx = np.where(tax_unit_ids == 442801)[0][0]\n", | |
| "tu2_idx = np.where(tax_unit_ids == 442802)[0][0]\n", | |
| "\n", | |
| "def get_value(var, idx):\n", | |
| " return sim.calculate(var, period=YEAR).values[idx]\n", | |
| "\n", | |
| "print(\"TAX UNIT 442801 (Parents + 4 kids):\")\n", | |
| "print(f\" AGI: ${get_value('adjusted_gross_income', tu1_idx):,.2f}\")\n", | |
| "print(f\" Itemizes: {bool(get_value('tax_unit_itemizes', tu1_idx))}\")\n", | |
| "print(f\" Deductions: ${get_value('taxable_income_deductions', tu1_idx):,.2f}\")\n", | |
| "print(f\" Tax: ${get_value('income_tax', tu1_idx):,.2f}\")\n", | |
| "print(f\" Tax if itemizing: ${get_value('tax_liability_if_itemizing', tu1_idx):,.2f}\")\n", | |
| "print(f\" Tax if standard: ${get_value('tax_liability_if_not_itemizing', tu1_idx):,.2f}\")\n", | |
| "\n", | |
| "print(\"\\nTAX UNIT 442802 (23-year-old):\")\n", | |
| "print(f\" AGI: ${get_value('adjusted_gross_income', tu2_idx):,.2f}\")\n", | |
| "print(f\" Itemizes: {bool(get_value('tax_unit_itemizes', tu2_idx))}\")\n", | |
| "print(f\" Deductions: ${get_value('taxable_income_deductions', tu2_idx):,.2f}\")\n", | |
| "print(f\" Tax: ${get_value('income_tax', tu2_idx):,.2f}\")\n", | |
| "\n", | |
| "print(\"\\n✓ Both tax units make rational decisions\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "## The Aggregation Issue\n", | |
| "\n", | |
| "When values are mapped to household level, confusing things happen:" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Get household-level values\n", | |
| "household_ids = sim.calculate(\"household_id\", map_to=\"household\", period=YEAR).values\n", | |
| "h_idx = np.where(household_ids == 4428)[0][0]\n", | |
| "\n", | |
| "h_itemizes = sim.calculate(\"tax_unit_itemizes\", map_to=\"household\", period=YEAR).values[h_idx]\n", | |
| "h_deductions = sim.calculate(\"taxable_income_deductions\", map_to=\"household\", period=YEAR).values[h_idx]\n", | |
| "h_tax_if_item = sim.calculate(\"tax_liability_if_itemizing\", map_to=\"household\", period=YEAR).values[h_idx]\n", | |
| "h_tax_if_std = sim.calculate(\"tax_liability_if_not_itemizing\", map_to=\"household\", period=YEAR).values[h_idx]\n", | |
| "\n", | |
| "print(\"HOUSEHOLD-LEVEL AGGREGATION:\")\n", | |
| "print(f\" Itemizes: {bool(h_itemizes)} (from first tax unit)\")\n", | |
| "print(f\" Total deductions: ${h_deductions:,.2f}\")\n", | |
| "print(f\" Tax if itemizing: ${h_tax_if_item:,.2f}\")\n", | |
| "print(f\" Tax if standard: ${h_tax_if_std:,.2f}\")\n", | |
| "\n", | |
| "print(\"\\nThis creates the false appearance that the household itemizes\") | |
| ", | |
| "print(\"despite worse tax outcomes, but it's really two separate decisions.\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "## The Deduction Mystery\n", | |
| "\n", | |
| "The $18,906.70 in household deductions comes from a later reform (likely senior deduction)\n", | |
| "that adds benefits to itemizers beyond just itemized deductions." | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3", | |
| "language": "python", | |
| "name": "python3" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 4 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment