From 74c6e4572c262751e4d32b6b565db4352c75dee7 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Mon, 12 Jan 2026 10:01:44 -0500 Subject: [PATCH] Marriage penalty analysis --- .../mn/hf1938/marriage_penalty_analysis.ipynb | 981 ++++++++++++++++++ .../mn/hf1938/marriage_penalty_results.csv | 51 + 2 files changed, 1032 insertions(+) create mode 100644 us/states/mn/hf1938/marriage_penalty_analysis.ipynb create mode 100644 us/states/mn/hf1938/marriage_penalty_results.csv diff --git a/us/states/mn/hf1938/marriage_penalty_analysis.ipynb b/us/states/mn/hf1938/marriage_penalty_analysis.ipynb new file mode 100644 index 0000000..f4f66d7 --- /dev/null +++ b/us/states/mn/hf1938/marriage_penalty_analysis.ipynb @@ -0,0 +1,981 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Marriage Penalty/Bonus Analysis\n", + "\n", + "Compare `income_tax + state_income_tax` between:\n", + "- **Factual**: actual marital status\n", + "- **Counterfactual**: flipped marital status\n", + "\n", + "Transformations:\n", + "- **Married → Single**: Spouse income combined into primary earner\n", + "- **Single → Married**: Add spouse with $0 income (tests bracket benefit)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from policyengine_us import Simulation\n", + "\n", + "YEAR = 2025" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total households: 112,502\n", + "Marital status: {1: 56604, 2: 55898}\n" + ] + } + ], + "source": [ + "# Load CPS data\n", + "df = pd.read_csv('/Users/pavelmakarchuk/analysis-notebooks/cps_households.csv')\n", + "df['total_wages'] = df['pwages'] + df['swages']\n", + "\n", + "print(f\"Total households: {len(df):,}\")\n", + "print(f\"Marital status: {df['mstat'].value_counts().to_dict()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Subset: 50 households with $30k-$150k wages\n", + "Married (mstat=2): 32\n", + "Single (mstat=1): 18\n" + ] + } + ], + "source": [ + "# Filter to households with meaningful earnings ($30k-$150k)\n", + "subset = df[(df['total_wages'] > 30000) & (df['total_wages'] < 150000)].head(50).copy()\n", + "\n", + "print(f\"Subset: {len(subset)} households with $30k-$150k wages\")\n", + "print(f\"Married (mstat=2): {(subset['mstat']==2).sum()}\")\n", + "print(f\"Single (mstat=1): {(subset['mstat']==1).sum()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "def create_situation_from_row(row, flip_marital_status=False):\n", + " \"\"\"Create a PolicyEngine situation from a TAXSIM row.\n", + " \n", + " If flip_marital_status=True:\n", + " - Married (mstat=2) becomes single: remove spouse, combine ALL incomes\n", + " - Single (mstat=1) becomes married: add spouse with $0 income\n", + " \"\"\"\n", + " is_married = row['mstat'] == 2\n", + " \n", + " # Determine effective marital status\n", + " if flip_marital_status:\n", + " effective_married = not is_married\n", + " else:\n", + " effective_married = is_married\n", + " \n", + " # Helper to safely get numeric values\n", + " def get_val(col):\n", + " return float(row.get(col, 0) or 0)\n", + " \n", + " # Primary earner income\n", + " primary_wages = get_val('pwages')\n", + " primary_self_emp = get_val('psemp')\n", + " \n", + " # Spouse income (only if originally married)\n", + " spouse_wages = get_val('swages') if is_married else 0\n", + " spouse_self_emp = get_val('ssemp') if is_married else 0\n", + " \n", + " # Shared income types (allocated to primary, will combine spouse if flipping)\n", + " dividends = get_val('dividends')\n", + " interest = get_val('intrec')\n", + " stcg = get_val('stcg')\n", + " ltcg = get_val('ltcg')\n", + " pensions = get_val('pensions')\n", + " social_security = get_val('gssi')\n", + " \n", + " # Build people\n", + " people = {\n", + " \"adult\": {\n", + " \"age\": {YEAR: int(row['page'])},\n", + " \"employment_income\": {YEAR: primary_wages},\n", + " \"self_employment_income\": {YEAR: primary_self_emp},\n", + " \"dividend_income\": {YEAR: dividends},\n", + " \"interest_income\": {YEAR: interest},\n", + " \"short_term_capital_gains\": {YEAR: stcg},\n", + " \"long_term_capital_gains\": {YEAR: ltcg},\n", + " \"pension_income\": {YEAR: pensions},\n", + " \"social_security\": {YEAR: social_security},\n", + " }\n", + " }\n", + " members = [\"adult\"]\n", + " marital_members = [\"adult\"]\n", + " \n", + " # Handle spouse\n", + " if effective_married:\n", + " if is_married and not flip_marital_status:\n", + " # Original married, staying married - spouse keeps their income\n", + " people[\"spouse\"] = {\n", + " \"age\": {YEAR: int(row['sage']) if row['sage'] > 0 else int(row['page'])},\n", + " \"employment_income\": {YEAR: spouse_wages},\n", + " \"self_employment_income\": {YEAR: spouse_self_emp},\n", + " }\n", + " else:\n", + " # Single becoming married - add spouse with $0 income\n", + " people[\"spouse\"] = {\n", + " \"age\": {YEAR: int(row['page'])},\n", + " \"employment_income\": {YEAR: 0},\n", + " }\n", + " members.append(\"spouse\")\n", + " marital_members.append(\"spouse\")\n", + " elif is_married and flip_marital_status:\n", + " # Married becoming single - combine ALL spouse income into adult\n", + " people[\"adult\"][\"employment_income\"][YEAR] += spouse_wages\n", + " people[\"adult\"][\"self_employment_income\"][YEAR] += spouse_self_emp\n", + " \n", + " # Add dependents\n", + " dep_ages = [row[f'age{i}'] for i in range(1, 12) if f'age{i}' in row and pd.notna(row[f'age{i}']) and row[f'age{i}'] > 0]\n", + " for i, age in enumerate(dep_ages):\n", + " dep_name = f\"child_{i}\"\n", + " people[dep_name] = {\"age\": {YEAR: int(age)}}\n", + " members.append(dep_name)\n", + " \n", + " situation = {\n", + " \"people\": people,\n", + " \"families\": {\"family\": {\"members\": members}},\n", + " \"marital_units\": {\"marital_unit\": {\"members\": marital_members}},\n", + " \"tax_units\": {\"tax_unit\": {\"members\": members}},\n", + " \"households\": {\n", + " \"household\": {\n", + " \"members\": members,\n", + " \"state_name\": {YEAR: \"MN\"},\n", + " }\n", + " },\n", + " }\n", + " \n", + " return situation" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_taxes(situation):\n", + " \"\"\"Calculate income_tax + state_income_tax for a situation.\"\"\"\n", + " sim = Simulation(situation=situation)\n", + " income_tax = sim.calculate(\"income_tax\", YEAR)\n", + " state_income_tax = sim.calculate(\"state_income_tax\", YEAR)\n", + " return float(income_tax.sum() + state_income_tax.sum())" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Processed 50 households\n" + ] + } + ], + "source": [ + "# Calculate factual and counterfactual taxes for each household\n", + "results = []\n", + "\n", + "for idx, row in subset.iterrows():\n", + " try:\n", + " # Factual (actual marital status)\n", + " factual_situation = create_situation_from_row(row, flip_marital_status=False)\n", + " factual_tax = calculate_taxes(factual_situation)\n", + " \n", + " # Counterfactual (flipped marital status)\n", + " counterfactual_situation = create_situation_from_row(row, flip_marital_status=True)\n", + " counterfactual_tax = calculate_taxes(counterfactual_situation)\n", + " \n", + " results.append({\n", + " 'taxsimid': row['taxsimid'],\n", + " 'original_mstat': 'married' if row['mstat'] == 2 else 'single',\n", + " 'pwages': row['pwages'],\n", + " 'swages': row['swages'],\n", + " 'depx': row['depx'],\n", + " 'factual_tax': factual_tax,\n", + " 'counterfactual_tax': counterfactual_tax,\n", + " 'marriage_penalty': counterfactual_tax - factual_tax if row['mstat'] == 1 else factual_tax - counterfactual_tax,\n", + " })\n", + " except Exception as e:\n", + " print(f\"Error on row {idx}: {e}\")\n", + "\n", + "results_df = pd.DataFrame(results)\n", + "print(f\"Processed {len(results_df)} households\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
taxsimidoriginal_mstatpwagesswagesdepxfactual_taxcounterfactual_taxmarriage_penalty
02.0married0.00000041904.7619050.01840.7558594437.500977-2596.745117
18.0married0.00000064668.4761901.04775.8310555551.355957-775.524902
212.0married45047.61904826190.4761900.06691.18457010651.116211-3959.931641
317.0single83809.5238100.0000000.014271.6875008969.470703-5302.216797
425.0single75428.5714290.0000002.04332.1059572867.181641-1464.924316
526.0married55824.4761900.0000000.04016.9218756977.046387-2960.124512
628.0single44000.0000000.0000000.04801.0249022162.375000-2638.649902
729.0single31428.5714290.0000001.0-6190.179688-8171.620117-1981.440430
830.0married77523.80952428809.5238100.013203.94726620758.546875-7554.599609
936.0married41904.76190518857.1428570.07874.58642613305.869141-5431.282715
1038.0single52380.9523810.0000000.06329.6640623448.851074-2880.812988
1139.0single68095.2380950.0000000.09745.9726566145.898438-3600.074219
1244.0married23329.42857154476.1904760.07943.89257812700.588867-4756.696289
1345.0married41904.7619050.0000000.04705.3867199933.289062-5227.902344
1448.0married83809.52381029483.1428572.09811.90136714044.822266-4232.920898
1556.0married0.000000104761.9047621.022060.53710928406.324219-6345.787109
1657.0single31428.5714290.0000000.04989.2631841377.149658-3612.113525
1761.0married0.00000061809.5238101.02780.7539064213.653809-1432.899902
1862.0single41904.7619050.0000001.0-1602.751709-4629.322754-3026.571045
1963.0married41904.7619050.0000001.03358.9326176225.772461-2866.839844
\n", + "
" + ], + "text/plain": [ + " taxsimid original_mstat pwages swages depx factual_tax \\\n", + "0 2.0 married 0.000000 41904.761905 0.0 1840.755859 \n", + "1 8.0 married 0.000000 64668.476190 1.0 4775.831055 \n", + "2 12.0 married 45047.619048 26190.476190 0.0 6691.184570 \n", + "3 17.0 single 83809.523810 0.000000 0.0 14271.687500 \n", + "4 25.0 single 75428.571429 0.000000 2.0 4332.105957 \n", + "5 26.0 married 55824.476190 0.000000 0.0 4016.921875 \n", + "6 28.0 single 44000.000000 0.000000 0.0 4801.024902 \n", + "7 29.0 single 31428.571429 0.000000 1.0 -6190.179688 \n", + "8 30.0 married 77523.809524 28809.523810 0.0 13203.947266 \n", + "9 36.0 married 41904.761905 18857.142857 0.0 7874.586426 \n", + "10 38.0 single 52380.952381 0.000000 0.0 6329.664062 \n", + "11 39.0 single 68095.238095 0.000000 0.0 9745.972656 \n", + "12 44.0 married 23329.428571 54476.190476 0.0 7943.892578 \n", + "13 45.0 married 41904.761905 0.000000 0.0 4705.386719 \n", + "14 48.0 married 83809.523810 29483.142857 2.0 9811.901367 \n", + "15 56.0 married 0.000000 104761.904762 1.0 22060.537109 \n", + "16 57.0 single 31428.571429 0.000000 0.0 4989.263184 \n", + "17 61.0 married 0.000000 61809.523810 1.0 2780.753906 \n", + "18 62.0 single 41904.761905 0.000000 1.0 -1602.751709 \n", + "19 63.0 married 41904.761905 0.000000 1.0 3358.932617 \n", + "\n", + " counterfactual_tax marriage_penalty \n", + "0 4437.500977 -2596.745117 \n", + "1 5551.355957 -775.524902 \n", + "2 10651.116211 -3959.931641 \n", + "3 8969.470703 -5302.216797 \n", + "4 2867.181641 -1464.924316 \n", + "5 6977.046387 -2960.124512 \n", + "6 2162.375000 -2638.649902 \n", + "7 -8171.620117 -1981.440430 \n", + "8 20758.546875 -7554.599609 \n", + "9 13305.869141 -5431.282715 \n", + "10 3448.851074 -2880.812988 \n", + "11 6145.898438 -3600.074219 \n", + "12 12700.588867 -4756.696289 \n", + "13 9933.289062 -5227.902344 \n", + "14 14044.822266 -4232.920898 \n", + "15 28406.324219 -6345.787109 \n", + "16 1377.149658 -3612.113525 \n", + "17 4213.653809 -1432.899902 \n", + "18 -4629.322754 -3026.571045 \n", + "19 6225.772461 -2866.839844 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# View results\n", + "results_df.head(20)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "=== Marriage Penalty/Bonus Summary ===\n", + "\n", + "Positive = marriage PENALTY (pay MORE when married)\n", + "Negative = marriage BONUS (pay LESS when married)\n", + "\n", + "Mean effect: $-4,017\n", + "Median effect: $-3,534\n", + "\n", + "Households with marriage penalty: 0\n", + "Households with marriage bonus: 50\n", + "Households with no change: 0\n", + "\n", + "=== Results Table ===\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
taxsimidoriginal_mstatpwagesswagesdepxfactual_taxcounterfactual_taxmarriage_penalty
02.0married0.00000041904.7619050.01840.7558594437.500977-2596.745117
18.0married0.00000064668.4761901.04775.8310555551.355957-775.524902
212.0married45047.61904826190.4761900.06691.18457010651.116211-3959.931641
317.0single83809.5238100.0000000.014271.6875008969.470703-5302.216797
425.0single75428.5714290.0000002.04332.1059572867.181641-1464.924316
526.0married55824.4761900.0000000.04016.9218756977.046387-2960.124512
628.0single44000.0000000.0000000.04801.0249022162.375000-2638.649902
729.0single31428.5714290.0000001.0-6190.179688-8171.620117-1981.440430
830.0married77523.80952428809.5238100.013203.94726620758.546875-7554.599609
936.0married41904.76190518857.1428570.07874.58642613305.869141-5431.282715
1038.0single52380.9523810.0000000.06329.6640623448.851074-2880.812988
1139.0single68095.2380950.0000000.09745.9726566145.898438-3600.074219
1244.0married23329.42857154476.1904760.07943.89257812700.588867-4756.696289
1345.0married41904.7619050.0000000.04705.3867199933.289062-5227.902344
1448.0married83809.52381029483.1428572.09811.90136714044.822266-4232.920898
1556.0married0.000000104761.9047621.022060.53710928406.324219-6345.787109
1657.0single31428.5714290.0000000.04989.2631841377.149658-3612.113525
1761.0married0.00000061809.5238101.02780.7539064213.653809-1432.899902
1862.0single41904.7619050.0000001.0-1602.751709-4629.322754-3026.571045
1963.0married41904.7619050.0000001.03358.9326176225.772461-2866.839844
\n", + "
" + ], + "text/plain": [ + " taxsimid original_mstat pwages swages depx factual_tax \\\n", + "0 2.0 married 0.000000 41904.761905 0.0 1840.755859 \n", + "1 8.0 married 0.000000 64668.476190 1.0 4775.831055 \n", + "2 12.0 married 45047.619048 26190.476190 0.0 6691.184570 \n", + "3 17.0 single 83809.523810 0.000000 0.0 14271.687500 \n", + "4 25.0 single 75428.571429 0.000000 2.0 4332.105957 \n", + "5 26.0 married 55824.476190 0.000000 0.0 4016.921875 \n", + "6 28.0 single 44000.000000 0.000000 0.0 4801.024902 \n", + "7 29.0 single 31428.571429 0.000000 1.0 -6190.179688 \n", + "8 30.0 married 77523.809524 28809.523810 0.0 13203.947266 \n", + "9 36.0 married 41904.761905 18857.142857 0.0 7874.586426 \n", + "10 38.0 single 52380.952381 0.000000 0.0 6329.664062 \n", + "11 39.0 single 68095.238095 0.000000 0.0 9745.972656 \n", + "12 44.0 married 23329.428571 54476.190476 0.0 7943.892578 \n", + "13 45.0 married 41904.761905 0.000000 0.0 4705.386719 \n", + "14 48.0 married 83809.523810 29483.142857 2.0 9811.901367 \n", + "15 56.0 married 0.000000 104761.904762 1.0 22060.537109 \n", + "16 57.0 single 31428.571429 0.000000 0.0 4989.263184 \n", + "17 61.0 married 0.000000 61809.523810 1.0 2780.753906 \n", + "18 62.0 single 41904.761905 0.000000 1.0 -1602.751709 \n", + "19 63.0 married 41904.761905 0.000000 1.0 3358.932617 \n", + "\n", + " counterfactual_tax marriage_penalty \n", + "0 4437.500977 -2596.745117 \n", + "1 5551.355957 -775.524902 \n", + "2 10651.116211 -3959.931641 \n", + "3 8969.470703 -5302.216797 \n", + "4 2867.181641 -1464.924316 \n", + "5 6977.046387 -2960.124512 \n", + "6 2162.375000 -2638.649902 \n", + "7 -8171.620117 -1981.440430 \n", + "8 20758.546875 -7554.599609 \n", + "9 13305.869141 -5431.282715 \n", + "10 3448.851074 -2880.812988 \n", + "11 6145.898438 -3600.074219 \n", + "12 12700.588867 -4756.696289 \n", + "13 9933.289062 -5227.902344 \n", + "14 14044.822266 -4232.920898 \n", + "15 28406.324219 -6345.787109 \n", + "16 1377.149658 -3612.113525 \n", + "17 4213.653809 -1432.899902 \n", + "18 -4629.322754 -3026.571045 \n", + "19 6225.772461 -2866.839844 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Summary statistics\n", + "print(\"=== Marriage Penalty/Bonus Summary ===\")\n", + "print(f\"\\nPositive = marriage PENALTY (pay MORE when married)\")\n", + "print(f\"Negative = marriage BONUS (pay LESS when married)\")\n", + "print(f\"\\nMean effect: ${results_df['marriage_penalty'].mean():,.0f}\")\n", + "print(f\"Median effect: ${results_df['marriage_penalty'].median():,.0f}\")\n", + "print(f\"\\nHouseholds with marriage penalty: {(results_df['marriage_penalty'] > 0).sum()}\")\n", + "print(f\"Households with marriage bonus: {(results_df['marriage_penalty'] < 0).sum()}\")\n", + "print(f\"Households with no change: {(results_df['marriage_penalty'] == 0).sum()}\")\n", + "\n", + "# Summary table\n", + "print(\"\\n=== Results Table ===\")\n", + "display_cols = ['taxsimid', 'original_mstat', 'pwages', 'swages', 'depx', 'factual_tax', 'counterfactual_tax', 'marriage_penalty']\n", + "results_df[display_cols].head(20)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "=== By Original Marital Status ===\n", + "\n", + "SINGLE households (n=18):\n", + " Mean marriage effect: $-3,355\n", + " Avg factual tax: $5,900\n", + " Avg counterfactual tax: $2,545\n", + "\n", + "MARRIED households (n=32):\n", + " Mean marriage effect: $-4,389\n", + " Avg factual tax: $7,781\n", + " Avg counterfactual tax: $12,171\n" + ] + } + ], + "source": [ + "# Breakdown by original marital status\n", + "print(\"=== By Original Marital Status ===\")\n", + "for status in ['single', 'married']:\n", + " subset_status = results_df[results_df['original_mstat'] == status]\n", + " if len(subset_status) > 0:\n", + " print(f\"\\n{status.upper()} households (n={len(subset_status)}):\")\n", + " print(f\" Mean marriage effect: ${subset_status['marriage_penalty'].mean():,.0f}\")\n", + " print(f\" Avg factual tax: ${subset_status['factual_tax'].mean():,.0f}\")\n", + " print(f\" Avg counterfactual tax: ${subset_status['counterfactual_tax'].mean():,.0f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved 50 rows to marriage_penalty_results.csv\n" + ] + } + ], + "source": [ + "# Export results to CSV\n", + "results_df.to_csv('marriage_penalty_results.csv', index=False)\n", + "print(f\"Saved {len(results_df)} rows to marriage_penalty_results.csv\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/us/states/mn/hf1938/marriage_penalty_results.csv b/us/states/mn/hf1938/marriage_penalty_results.csv new file mode 100644 index 0000000..ec9a3d8 --- /dev/null +++ b/us/states/mn/hf1938/marriage_penalty_results.csv @@ -0,0 +1,51 @@ +taxsimid,original_mstat,pwages,swages,depx,factual_tax,counterfactual_tax,marriage_penalty +2.0,married,0.0,41904.76190476191,0.0,1840.755859375,4437.5009765625,-2596.7451171875 +8.0,married,0.0,64668.47619047619,1.0,4775.8310546875,5551.35595703125,-775.52490234375 +12.0,married,45047.61904761905,26190.47619047619,0.0,6691.1845703125,10651.1162109375,-3959.931640625 +17.0,single,83809.52380952382,0.0,0.0,14271.6875,8969.470703125,-5302.216796875 +25.0,single,75428.57142857143,0.0,2.0,4332.10595703125,2867.181640625,-1464.92431640625 +26.0,married,55824.47619047619,0.0,0.0,4016.921875,6977.04638671875,-2960.12451171875 +28.0,single,44000.0,0.0,0.0,4801.02490234375,2162.375,-2638.64990234375 +29.0,single,31428.57142857143,0.0,1.0,-6190.1796875,-8171.6201171875,-1981.4404296875 +30.0,married,77523.80952380953,28809.52380952381,0.0,13203.947265625,20758.546875,-7554.599609375 +36.0,married,41904.76190476191,18857.14285714286,0.0,7874.58642578125,13305.869140625,-5431.28271484375 +38.0,single,52380.95238095238,0.0,0.0,6329.6640625,3448.85107421875,-2880.81298828125 +39.0,single,68095.23809523809,0.0,0.0,9745.97265625,6145.8984375,-3600.07421875 +44.0,married,23329.428571428572,54476.19047619048,0.0,7943.892578125,12700.5888671875,-4756.6962890625 +45.0,married,41904.76190476191,0.0,0.0,4705.38671875,9933.2890625,-5227.90234375 +48.0,married,83809.52380952382,29483.14285714286,2.0,9811.9013671875,14044.822265625,-4232.9208984375 +56.0,married,0.0,104761.90476190476,1.0,22060.537109375,28406.32421875,-6345.787109375 +57.0,single,31428.57142857143,0.0,0.0,4989.26318359375,1377.149658203125,-3612.113525390625 +61.0,married,0.0,61809.52380952381,1.0,2780.75390625,4213.65380859375,-1432.89990234375 +62.0,single,41904.76190476191,0.0,1.0,-1602.751708984375,-4629.32275390625,-3026.571044921875 +63.0,married,41904.76190476191,0.0,1.0,3358.9326171875,6225.7724609375,-2866.83984375 +66.0,married,36666.66666666667,0.0,1.0,-6873.388671875,-3920.512939453125,-2952.875732421875 +67.0,married,69142.85714285714,0.0,0.0,7381.5712890625,11643.890625,-4262.3193359375 +68.0,single,69142.85714285714,0.0,0.0,18552.736328125,10816.99609375,-7735.740234375 +70.0,single,73333.33333333334,0.0,1.0,6288.40234375,4779.18408203125,-1509.21826171875 +71.0,single,73333.33333333334,0.0,0.0,11254.5458984375,7054.708984375,-4199.8369140625 +83.0,married,64952.380952380954,20549.04761904762,0.0,9287.548828125,14758.95703125,-5471.408203125 +85.0,married,0.0,73333.33333333334,0.0,6779.7841796875,11254.5458984375,-4474.76171875 +86.0,married,0.0,47142.857142857145,0.0,8136.34375,13272.732421875,-5136.388671875 +91.0,married,62857.14285714286,57619.04761904762,0.0,18063.30859375,29094.29296875,-11030.984375 +93.0,married,52380.95238095238,0.0,1.0,-89.98928833007812,2576.84521484375,-2666.834503173828 +95.0,married,69142.85714285714,50285.71428571429,1.0,13063.919921875,18163.48046875,-5099.560546875 +96.0,married,40857.14285714286,27238.09523809524,1.0,3898.633544921875,5337.41796875,-1438.784423828125 +97.0,single,39809.52380952381,0.0,0.0,3729.65234375,974.6915893554688,-2754.9607543945312 +100.0,married,0.0,31428.57142857143,4.0,1505.756591796875,2281.282958984375,-775.5263671875 +101.0,married,0.0,31428.57142857143,0.0,-78.52880859375,3240.96923828125,-3319.498046875 +102.0,married,91142.85714285714,58666.66666666667,2.0,22355.76953125,28786.798828125,-6431.029296875 +104.0,single,59714.28571428572,0.0,0.0,8426.734375,4878.43505859375,-3548.29931640625 +106.0,married,0.0,73333.33333333334,0.0,9001.6728515625,15007.22265625,-6005.5498046875 +109.0,married,0.0,104761.90476190476,0.0,13705.78515625,22592.529296875,-8886.744140625 +110.0,single,86952.38095238096,0.0,0.0,15176.83203125,9560.328125,-5616.50390625 +112.0,single,31428.57142857143,0.0,0.0,2283.7109375,-144.13914489746094,-2427.850082397461 +120.0,married,36666.66666666667,39809.52380952381,2.0,4548.943359375,5324.46875,-775.525390625 +121.0,single,64952.380952380954,0.0,0.0,8840.83203125,5600.61328125,-3240.21875 +122.0,married,53266.19047619048,45047.61904761905,0.0,11475.8388671875,18448.923828125,-6973.0849609375 +124.0,single,59714.28571428572,0.0,0.0,7708.3310546875,4691.80322265625,-3016.52783203125 +125.0,married,36666.66666666667,13619.04761904762,0.0,6155.8740234375,9676.244140625,-3520.3701171875 +131.0,married,7899.047619047619,57619.04761904762,1.0,6104.87890625,6880.40380859375,-775.52490234375 +132.0,married,39809.52380952381,52380.95238095238,2.0,5775.373046875,7967.392578125,-2192.01953125 +133.0,single,31428.57142857143,0.0,2.0,-12733.966796875,-14566.9248046875,-1832.9580078125 +134.0,married,0.0,136190.47619047618,0.0,19741.134765625,29864.6796875,-10123.544921875