|
86 | 86 | } |
87 | 87 | }, |
88 | 88 | "outputs": [], |
89 | | - "source": "def create_aei_reform():\n \"\"\"\n Creates a PolicyEngine reform that adds the California AEI rebate base variables.\n \n Returns:\n Reform: PolicyEngine reform with ca_aei_rebate_base variables\n \"\"\"\n \n class household_fpg(Variable):\n value_type = float\n entity = Household\n label = \"Household's federal poverty guideline\"\n definition_period = YEAR\n unit = USD\n\n def formula(household, period, parameters):\n n = household(\"household_size\", period)\n state_group = household(\"state_group_str\", period)\n p_fpg = parameters(period).gov.hhs.fpg\n p1 = p_fpg.first_person[state_group]\n pn = p_fpg.additional_person[state_group]\n return p1 + pn * (n - 1)\n \n class ca_aei_rebate_base_tax_unit(Variable):\n value_type = float\n entity = TaxUnit\n label = \"California AEI rebate base (tax unit version)\"\n unit = USD\n definition_period = YEAR\n defined_for = StateCode.CA\n\n def formula(tax_unit, period, parameters):\n # Use tax unit's own AGI\n income = tax_unit(\"adjusted_gross_income\", period)\n fpg = tax_unit(\"tax_unit_fpg\", period)\n income_to_fpg_ratio = where(fpg > 0, income / fpg, np.inf)\n\n # Phase-out parameters\n PHASEOUT_START = 1.5 # 150% FPG\n PHASEOUT_END = 1.75 # 175% FPG\n phaseout_width = PHASEOUT_END - PHASEOUT_START\n\n # Phase-out calculation\n excess = max_(income_to_fpg_ratio - PHASEOUT_START, 0)\n phaseout_percentage = min_(1, excess / phaseout_width)\n\n return where(\n income_to_fpg_ratio <= PHASEOUT_END,\n fpg * (1 - phaseout_percentage),\n 0\n )\n\n class ca_aei_rebate_base(Variable):\n value_type = float\n entity = Household\n label = \"California AEI rebate base\"\n unit = USD\n definition_period = YEAR\n\n def formula(household, period, parameters):\n # Sum AGI from all tax units in the household\n income = household.sum(household.members.tax_unit(\"adjusted_gross_income\", period))\n fpg = household(\"household_fpg\", period)\n income_to_fpg_ratio = where(fpg > 0, income / fpg, np.inf)\n\n # Phase-out parameters\n PHASEOUT_START = 1.5 # 150% FPG\n PHASEOUT_END = 1.75 # 175% FPG\n phaseout_width = PHASEOUT_END - PHASEOUT_START\n\n # Phase-out calculation\n excess = max_(income_to_fpg_ratio - PHASEOUT_START, 0)\n phaseout_percentage = min_(1, excess / phaseout_width)\n\n return where(\n income_to_fpg_ratio <= PHASEOUT_END,\n fpg * (1 - phaseout_percentage),\n 0\n )\n\n class AEIReform(Reform):\n def apply(self):\n self.update_variable(household_fpg)\n self.update_variable(ca_aei_rebate_base_tax_unit)\n self.update_variable(ca_aei_rebate_base)\n \n return AEIReform\n\nprint(\"Reform defined successfully\")" |
| 89 | + "source": "def create_aei_reform():\n \"\"\"\n Creates a PolicyEngine reform that adds the California AEI rebate base variables.\n \n Returns:\n Reform: PolicyEngine reform with ca_aei_rebate_base variables\n \"\"\"\n \n class household_fpg(Variable):\n value_type = float\n entity = Household\n label = \"Household's federal poverty guideline\"\n definition_period = YEAR\n unit = USD\n\n def formula(household, period, parameters):\n n = household(\"household_size\", period)\n state_group = household(\"state_group_str\", period)\n p_fpg = parameters(period).gov.hhs.fpg\n p1 = p_fpg.first_person[state_group]\n pn = p_fpg.additional_person[state_group]\n return p1 + pn * (n - 1)\n \n class ca_aei_rebate_base_tax_unit(Variable):\n value_type = float\n entity = TaxUnit\n label = \"California AEI rebate base (tax unit version)\"\n unit = USD\n definition_period = YEAR\n defined_for = StateCode.CA\n\n def formula(tax_unit, period, parameters):\n # Use tax unit's own AGI\n income = tax_unit(\"adjusted_gross_income\", period)\n fpg = tax_unit(\"tax_unit_fpg\", period)\n income_to_fpg_ratio = where(fpg > 0, income / fpg, np.inf)\n\n # Phase-out parameters\n PHASEOUT_START = 1.5 # 150% FPG\n PHASEOUT_END = 1.75 # 175% FPG\n phaseout_width = PHASEOUT_END - PHASEOUT_START\n\n # Phase-out calculation\n excess = max_(income_to_fpg_ratio - PHASEOUT_START, 0)\n phaseout_percentage = min_(1, excess / phaseout_width)\n\n return fpg * (1 - phaseout_percentage)\n\n class ca_aei_rebate_base_household(Variable):\n value_type = float\n entity = Household\n label = \"California AEI rebate base (household version)\"\n unit = USD\n definition_period = YEAR\n\n def formula(household, period, parameters):\n # Sum AGI from all tax units in the household\n income = household.sum(household.members.tax_unit(\"adjusted_gross_income\", period))\n fpg = household(\"household_fpg\", period)\n income_to_fpg_ratio = where(fpg > 0, income / fpg, np.inf)\n\n # Phase-out parameters\n PHASEOUT_START = 1.5 # 150% FPG\n PHASEOUT_END = 1.75 # 175% FPG\n phaseout_width = PHASEOUT_END - PHASEOUT_START\n\n # Phase-out calculation\n excess = max_(income_to_fpg_ratio - PHASEOUT_START, 0)\n phaseout_percentage = min_(1, excess / phaseout_width)\n\n return fpg * (1 - phaseout_percentage)\n\n class AEIReform(Reform):\n def apply(self):\n self.update_variable(household_fpg)\n self.update_variable(ca_aei_rebate_base_tax_unit)\n self.update_variable(ca_aei_rebate_base_household)\n \n return AEIReform\n\nprint(\"Reform defined successfully\")" |
90 | 90 | }, |
91 | 91 | { |
92 | 92 | "cell_type": "markdown", |
|
97 | 97 | }, |
98 | 98 | { |
99 | 99 | "cell_type": "code", |
100 | | - "execution_count": 3, |
| 100 | + "execution_count": null, |
101 | 101 | "metadata": { |
102 | 102 | "execution": { |
103 | 103 | "iopub.execute_input": "2025-09-15T18:56:46.866675Z", |
|
106 | 106 | "shell.execute_reply": "2025-09-15T18:56:58.429120Z" |
107 | 107 | } |
108 | 108 | }, |
109 | | - "outputs": [ |
110 | | - { |
111 | | - "name": "stdout", |
112 | | - "output_type": "stream", |
113 | | - "text": [ |
114 | | - "Loading data and creating simulation...\n" |
115 | | - ] |
116 | | - }, |
117 | | - { |
118 | | - "name": "stdout", |
119 | | - "output_type": "stream", |
120 | | - "text": [ |
121 | | - "Calculating household statistics for 2026...\n" |
122 | | - ] |
123 | | - }, |
124 | | - { |
125 | | - "name": "stdout", |
126 | | - "output_type": "stream", |
127 | | - "text": [ |
128 | | - "Calculating tax_unit statistics for 2026...\n" |
129 | | - ] |
130 | | - } |
131 | | - ], |
132 | | - "source": [ |
133 | | - "def calculate_rebate_base_statistics(sim, unit_type=\"household\", year=2026):\n", |
134 | | - " \"\"\"\n", |
135 | | - " Calculate AEI rebate base program statistics for California households or tax units.\n", |
136 | | - " \n", |
137 | | - " Args:\n", |
138 | | - " sim: Microsimulation object with reform applied\n", |
139 | | - " unit_type: Either \"household\" or \"tax_unit\"\n", |
140 | | - " year: Year to calculate for\n", |
141 | | - " \n", |
142 | | - " Returns:\n", |
143 | | - " Dictionary with rebate base statistics\n", |
144 | | - " \"\"\"\n", |
145 | | - " print(f\"Calculating {unit_type} statistics for {year}...\")\n", |
146 | | - " \n", |
147 | | - " if unit_type == \"household\":\n", |
148 | | - " # Calculate rebate base for all households\n", |
149 | | - " rebate_base = sim.calculate(\"ca_aei_rebate_base\", year)\n", |
150 | | - " \n", |
151 | | - " # Filter for California households only\n", |
152 | | - " household_state = sim.calculate(\"state_code\", year, map_to=\"household\")\n", |
153 | | - " ca_mask = household_state == \"CA\"\n", |
154 | | - " \n", |
155 | | - " # Apply CA filter\n", |
156 | | - " ca_rebate_base = rebate_base[ca_mask]\n", |
157 | | - " total_ca_units = ca_mask.sum()\n", |
158 | | - " \n", |
159 | | - " else: # tax_unit\n", |
160 | | - " # Calculate rebate base for all tax units (defined_for gives 0 for non-CA)\n", |
161 | | - " rebate_base = sim.calculate(\"ca_aei_rebate_base_tax_unit\", year)\n", |
162 | | - " \n", |
163 | | - " # Use calculate_dataframe to get household-level data\n", |
164 | | - " household_df = sim.calculate_dataframe(\n", |
165 | | - " [\"household_id\", \"state_code\"],\n", |
166 | | - " year,\n", |
167 | | - " map_to=\"household\"\n", |
168 | | - " )\n", |
169 | | - " \n", |
170 | | - " # Get tax unit data\n", |
171 | | - " tax_unit_df = sim.calculate_dataframe(\n", |
172 | | - " [\"tax_unit_id\", \"tax_unit_household_id\"],\n", |
173 | | - " year\n", |
174 | | - " )\n", |
175 | | - " \n", |
176 | | - " # Merge to get state for each tax unit\n", |
177 | | - " tax_unit_with_state = tax_unit_df.merge(\n", |
178 | | - " household_df[[\"household_id\", \"state_code\"]],\n", |
179 | | - " left_on=\"tax_unit_household_id\",\n", |
180 | | - " right_on=\"household_id\",\n", |
181 | | - " how=\"left\"\n", |
182 | | - " )\n", |
183 | | - " \n", |
184 | | - " # Create a boolean MicroSeries for CA tax units\n", |
185 | | - " ca_tax_unit_mask = tax_unit_with_state[\"state_code\"] == \"CA\"\n", |
186 | | - " total_ca_units = ca_tax_unit_mask.sum()\n", |
187 | | - " \n", |
188 | | - " # For tax units, we use all rebates (defined_for already filters to CA)\n", |
189 | | - " ca_rebate_base = rebate_base\n", |
190 | | - " \n", |
191 | | - " # Calculate statistics (MicroSeries already contain weights)\n", |
192 | | - " units_with_rebate = (ca_rebate_base > 0).sum()\n", |
193 | | - " total_rebate_base = ca_rebate_base.sum()\n", |
194 | | - " average_rebate_base = ca_rebate_base[ca_rebate_base > 0].mean() if units_with_rebate > 0 else 0\n", |
195 | | - " \n", |
196 | | - " return {\n", |
197 | | - " \"unit_type\": unit_type,\n", |
198 | | - " \"total_ca_units\": total_ca_units,\n", |
199 | | - " \"units_with_rebate\": units_with_rebate,\n", |
200 | | - " \"rebate_percentage\": units_with_rebate / total_ca_units,\n", |
201 | | - " \"average_rebate_base\": average_rebate_base,\n", |
202 | | - " \"total_rebate_base\": total_rebate_base,\n", |
203 | | - " }\n", |
204 | | - "\n", |
205 | | - "# Create simulation once\n", |
206 | | - "print(\"Loading data and creating simulation...\")\n", |
207 | | - "reform = create_aei_reform()\n", |
208 | | - "sim = Microsimulation(\n", |
209 | | - " dataset=\"hf://policyengine/policyengine-us-data/pooled_3_year_cps_2023.h5\",\n", |
210 | | - " reform=reform\n", |
211 | | - ")\n", |
212 | | - "\n", |
213 | | - "# Calculate both household and tax unit results using the same simulation\n", |
214 | | - "household_results = calculate_rebate_base_statistics(sim, \"household\", SIMULATION_YEAR)\n", |
215 | | - "tax_unit_results = calculate_rebate_base_statistics(sim, \"tax_unit\", SIMULATION_YEAR)" |
216 | | - ] |
| 109 | + "outputs": [], |
| 110 | + "source": "def calculate_rebate_base_statistics(sim, unit_type=\"household\", year=2026):\n \"\"\"\n Calculate AEI rebate base program statistics for California households or tax units.\n \n Args:\n sim: Microsimulation object with reform applied\n unit_type: Either \"household\" or \"tax_unit\"\n year: Year to calculate for\n \n Returns:\n Dictionary with rebate base statistics\n \"\"\"\n print(f\"Calculating {unit_type} statistics for {year}...\")\n \n if unit_type == \"household\":\n # Calculate rebate base for all households\n rebate_base = sim.calculate(\"ca_aei_rebate_base_household\", year)\n \n # Filter for California households only\n household_state = sim.calculate(\"state_code\", year, map_to=\"household\")\n ca_mask = household_state == \"CA\"\n \n # Apply CA filter\n ca_rebate_base = rebate_base[ca_mask]\n total_ca_units = ca_mask.sum()\n \n else: # tax_unit\n # Calculate rebate base for all tax units (defined_for gives 0 for non-CA)\n rebate_base = sim.calculate(\"ca_aei_rebate_base_tax_unit\", year)\n \n # Use calculate_dataframe to get household-level data\n household_df = sim.calculate_dataframe(\n [\"household_id\", \"state_code\"],\n year,\n map_to=\"household\"\n )\n \n # Get tax unit data\n tax_unit_df = sim.calculate_dataframe(\n [\"tax_unit_id\", \"tax_unit_household_id\"],\n year\n )\n \n # Merge to get state for each tax unit\n tax_unit_with_state = tax_unit_df.merge(\n household_df[[\"household_id\", \"state_code\"]],\n left_on=\"tax_unit_household_id\",\n right_on=\"household_id\",\n how=\"left\"\n )\n \n # Create a boolean MicroSeries for CA tax units\n ca_tax_unit_mask = tax_unit_with_state[\"state_code\"] == \"CA\"\n total_ca_units = ca_tax_unit_mask.sum()\n \n # For tax units, we use all rebates (defined_for already filters to CA)\n ca_rebate_base = rebate_base\n \n # Calculate statistics (MicroSeries already contain weights)\n units_with_rebate = (ca_rebate_base > 0).sum()\n total_rebate_base = ca_rebate_base.sum()\n average_rebate_base = ca_rebate_base[ca_rebate_base > 0].mean() if units_with_rebate > 0 else 0\n \n return {\n \"unit_type\": unit_type,\n \"total_ca_units\": total_ca_units,\n \"units_with_rebate\": units_with_rebate,\n \"rebate_percentage\": units_with_rebate / total_ca_units,\n \"average_rebate_base\": average_rebate_base,\n \"total_rebate_base\": total_rebate_base,\n }\n\n# Create simulation once\nprint(\"Loading data and creating simulation...\")\nreform = create_aei_reform()\nsim = Microsimulation(\n dataset=\"hf://policyengine/policyengine-us-data/pooled_3_year_cps_2023.h5\",\n reform=reform\n)\n\n# Calculate both household and tax unit results using the same simulation\nhousehold_results = calculate_rebate_base_statistics(sim, \"household\", SIMULATION_YEAR)\ntax_unit_results = calculate_rebate_base_statistics(sim, \"tax_unit\", SIMULATION_YEAR)" |
217 | 111 | }, |
218 | 112 | { |
219 | 113 | "cell_type": "markdown", |
|
0 commit comments