Skip to content

Commit af8b4a7

Browse files
vahid-ahmadiclaude
andauthored
Expand Universal Credit documentation page (#745) (#1700)
* Expand Universal Credit docs page (#745) The existing page covered six legacy benefits, gave the Welfare Reform Act 2012 link, and showed a chart of selected element rates. Round it out with: - a "How PolicyEngine computes Universal Credit" section explaining the uc_maximum_amount -> means test -> benefit cap pipeline and the would_claim_uc take-up input, - a References section pointing at the primary statute (WRA 2012), the operational regs (SI 2013/376), the annual DWP rate uprating publication, and the UC official statistics page that policyengine-uk-data calibrates against, - fix the rates dataframe so it builds in one pass instead of pd.concat in a loop (which raised FutureWarning) and corrects the "Amount(£m)" axis label to "Amount (£/month)", - drop an empty trailing code cell. * Fix taper-rate reference in UC docs uc_earnings_taper_rate does not exist; the UC taper is the gov.dwp.universal_credit.means_test.reduction_rate parameter (55%). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 2340bc0 commit af8b4a7

2 files changed

Lines changed: 26 additions & 29 deletions

File tree

changelog.d/745.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Expand the Universal Credit documentation page: add a "How PolicyEngine computes Universal Credit" section walking through `uc_maximum_amount` -> means test -> benefit cap, add a references block (Welfare Reform Act 2012, SI 2013/376, DWP rate uprating, official statistics), tidy the elements rates dataframe to drop the pd.concat-in-loop pattern, fix the £/month axis label, and remove an empty trailing cell.

docs/book/programs/gov/dwp/universal-credit.ipynb

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"* Housing Benefit for working-age claimants: Helps people with the cost of their rent if they are on a \n",
2323
" low income.\n",
2424
"\n",
25-
"Universal Credit parameters can be found in `policyengine_uk/parameters/gov/dwp/universal_credit` and logic in `policyengine_uk/variables/dwp/universal_credit.py`.\n",
25+
"Universal Credit parameters live in `policyengine_uk/parameters/gov/dwp/universal_credit/` and the per-element formulas in `policyengine_uk/variables/gov/dwp/universal_credit/`.\n",
2626
"\n",
2727
"## Legislation\n",
2828
"\n",
@@ -41,6 +41,11 @@
4141
"The table below shows some of the rates covered by PolicyEngine-UK. "
4242
]
4343
},
44+
{
45+
"cell_type": "markdown",
46+
"metadata": {},
47+
"source": "## How PolicyEngine computes Universal Credit\n\nPolicyEngine computes Universal Credit at the benefit-unit level in three stages:\n\n1. **Maximum entitlement** (`uc_maximum_amount`): sum the elements the benunit qualifies for — `uc_standard_allowance`, `uc_child_element`, `uc_disability_elements`, `uc_carer_element`, `uc_housing_costs_element`, and `uc_childcare_element`.\n2. **Means test**: the maximum entitlement is reduced by the benunit's countable earnings above its work allowance (`uc_work_allowance`) at the published taper rate (the `gov.dwp.universal_credit.means_test.reduction_rate` parameter, currently 55%), plus its unearned income. Asset rules apply on top of this — capital above the lower threshold deems a tariff income, and capital above the upper threshold disqualifies the benunit entirely.\n3. **Benefit cap**: the post-means-test award (`universal_credit_pre_benefit_cap`) is finally reduced by `benefit_cap_reduction` to produce `universal_credit`. The benefit cap only applies to benunits without a benefit-cap exemption (working enough hours, having a qualifying disability benefit, etc.).\n\nThe take-up step is handled by the input variable `would_claim_uc`, which is populated stochastically when the dataset is built so that PolicyEngine's caseload aggregates match published DWP claimant numbers rather than the full eligible population.\n\nParameters live in `policyengine_uk/parameters/gov/dwp/universal_credit/` and the per-element formulas in `policyengine_uk/variables/gov/dwp/universal_credit/`."
48+
},
4449
{
4550
"cell_type": "code",
4651
"execution_count": 15,
@@ -202,34 +207,20 @@
202207
" disabled_amount,\n",
203208
" disabled_child_amount,\n",
204209
" higher_amount,\n",
205-
"] # [...]\n",
206-
"\n",
207-
"dates = [\n",
208-
" \"2016-01-01\",\n",
209-
" \"2017-01-01\",\n",
210-
" \"2018-01-01\",\n",
211-
" \"2019-01-01\",\n",
212-
" \"2020-01-01\",\n",
213-
" \"2021-01-01\",\n",
214-
" \"2022-01-01\",\n",
215-
" \"2023-01-01\",\n",
216-
" \"2024-01-01\",\n",
217210
"]\n",
218211
"names = [\"Carer\", \"Child\", \"Disabled\", \"Disabled child\", \"First child\"]\n",
219212
"\n",
220-
"import pandas as pd\n",
221-
"\n",
222-
"df = pd.DataFrame()\n",
213+
"dates = [f\"{year}-01-01\" for year in range(2016, 2025)]\n",
223214
"\n",
224-
"for date in dates:\n",
225-
" for element, name in zip(elements, names):\n",
226-
" # Append to a dataframe: row = date, column = element, value = amount\n",
227-
" new_row = {\"date\": date, \"element\": name, \"amount\": element(date)}\n",
228-
" # Append row to the dataframe\n",
229-
" df = pd.concat([df, pd.DataFrame([new_row])])\n",
215+
"import pandas as pd\n",
230216
"\n",
217+
"rows = [\n",
218+
" {\"date\": date, \"element\": name, \"amount\": element(date)}\n",
219+
" for date in dates\n",
220+
" for element, name in zip(elements, names)\n",
221+
"]\n",
222+
"df = pd.DataFrame(rows)\n",
231223
"\n",
232-
"# merge element cells\n",
233224
"pivot_df = df.pivot(index=\"date\", columns=\"element\", values=\"amount\")\n",
234225
"pivot_df.fillna(\"\")"
235226
]
@@ -1349,7 +1340,7 @@
13491340
" yaxis_range=[0, 500],\n",
13501341
" yaxis_tickformat=\",.0f\",\n",
13511342
" yaxis_tickprefix=\"£\",\n",
1352-
" yaxis_title=\"Amount(£m)\",\n",
1343+
" yaxis_title=\"Amount (£/month)\",\n",
13531344
" xaxis_title=\"Year\",\n",
13541345
" legend_title=\"Element\",\n",
13551346
")\n",
@@ -1359,11 +1350,16 @@
13591350
]
13601351
},
13611352
{
1362-
"cell_type": "code",
1363-
"execution_count": null,
1353+
"cell_type": "markdown",
13641354
"metadata": {},
1365-
"outputs": [],
1366-
"source": []
1355+
"source": [
1356+
"## References\n",
1357+
"\n",
1358+
"- [The Welfare Reform Act 2012](https://www.legislation.gov.uk/ukpga/2012/5/contents) — the primary statute creating Universal Credit.\n",
1359+
"- [The Universal Credit Regulations 2013 (SI 2013/376)](https://www.legislation.gov.uk/uksi/2013/376/contents) — the operational regulations.\n",
1360+
"- DWP, [Benefit and pension rates](https://www.gov.uk/government/publications/benefit-and-pension-rates-2025-to-2026) — annual rate uprating.\n",
1361+
"- DWP, [Universal Credit official statistics](https://www.gov.uk/government/collections/universal-credit-statistics) — caseload and expenditure outturns used by `policyengine-uk-data` for calibration."
1362+
]
13671363
}
13681364
],
13691365
"metadata": {
@@ -1388,4 +1384,4 @@
13881384
},
13891385
"nbformat": 4,
13901386
"nbformat_minor": 1
1391-
}
1387+
}

0 commit comments

Comments
 (0)