Skip to content

Instantly share code, notes, and snippets.

@MaxGhenis
Created July 25, 2025 23:44
Show Gist options
  • Save MaxGhenis/dbecbf2381217980e3890cbbe0f85708 to your computer and use it in GitHub Desktop.
Save MaxGhenis/dbecbf2381217980e3890cbbe0f85708 to your computer and use it in GitHub Desktop.
Resolution: Multiple tax units explain the itemization behavior
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Resolution: Household 4428 Has Multiple Tax Units\n",
"\n",
"The apparent bug is explained by household 4428 having 2 tax units with different itemization decisions."
]
},
{
"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",
"DATASET = \"hf://policyengine/policyengine-us-data/enhanced_cps_2024.h5\"\n",
"YEAR = 2026"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup Reform"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"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": [
"## Check Both Tax Units"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Get tax unit data\n",
"tax_unit_ids = sim.calculate(\"tax_unit_id\", period=YEAR).values\n",
"itemizes = sim.calculate(\"tax_unit_itemizes\", period=YEAR).values\n",
"tax_if_item = sim.calculate(\"tax_liability_if_itemizing\", period=YEAR).values\n",
"tax_if_std = sim.calculate(\"tax_liability_if_not_itemizing\", period=YEAR).values\n",
"\n",
"# Find the two tax units in household 4428\n",
"tu1_idx = np.where(tax_unit_ids == 442801)[0][0]\n",
"tu2_idx = np.where(tax_unit_ids == 442802)[0][0]\n",
"\n",
"print(\"Tax Unit 442801 (parents + 4 kids):\")\n",
"print(f\" Itemizes: {bool(itemizes[tu1_idx])}\")\n",
"print(f\" Tax if itemizing: ${tax_if_item[tu1_idx]:,.2f}\")\n",
"print(f\" Tax if standard: ${tax_if_std[tu1_idx]:,.2f}\")\n",
"print(f\" Optimal: {'Same either way' if tax_if_item[tu1_idx] == tax_if_std[tu1_idx] else 'Itemize' if tax_if_item[tu1_idx] < tax_if_std[tu1_idx] else 'Standard'}\")\n",
"\n",
"print(\"\\nTax Unit 442802 (23-year-old):\")\n",
"print(f\" Itemizes: {bool(itemizes[tu2_idx])}\")\n",
"print(f\" Tax if itemizing: ${tax_if_item[tu2_idx]:,.2f}\")\n",
"print(f\" Tax if standard: ${tax_if_std[tu2_idx]:,.2f}\")\n",
"print(f\" Optimal: {'Standard' if tax_if_std[tu2_idx] < tax_if_item[tu2_idx] else 'Itemize'}\")\n",
"\n",
"print(\"\\n✓ Both tax units make optimal decisions!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## The Real Issue\n",
"\n",
"The confusion arose from looking at household-level aggregates. When mapped to household level:\n",
"- `tax_unit_itemizes` shows True (from the first tax unit)\n",
"- But the tax liability values are summed across both tax units\n",
"\n",
"This creates the appearance of irrational behavior when it's actually two rational decisions."
]
}
],
"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