Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/745.md
Original file line number Diff line number Diff line change
@@ -0,0 +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.
54 changes: 25 additions & 29 deletions docs/book/programs/gov/dwp/universal-credit.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"* Housing Benefit for working-age claimants: Helps people with the cost of their rent if they are on a \n",
" low income.\n",
"\n",
"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",
"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",
"\n",
"## Legislation\n",
"\n",
Expand All @@ -41,6 +41,11 @@
"The table below shows some of the rates covered by PolicyEngine-UK. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"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/`."
},
{
"cell_type": "code",
"execution_count": 15,
Expand Down Expand Up @@ -202,34 +207,20 @@
" disabled_amount,\n",
" disabled_child_amount,\n",
" higher_amount,\n",
"] # [...]\n",
"\n",
"dates = [\n",
" \"2016-01-01\",\n",
" \"2017-01-01\",\n",
" \"2018-01-01\",\n",
" \"2019-01-01\",\n",
" \"2020-01-01\",\n",
" \"2021-01-01\",\n",
" \"2022-01-01\",\n",
" \"2023-01-01\",\n",
" \"2024-01-01\",\n",
"]\n",
"names = [\"Carer\", \"Child\", \"Disabled\", \"Disabled child\", \"First child\"]\n",
"\n",
"import pandas as pd\n",
"\n",
"df = pd.DataFrame()\n",
"dates = [f\"{year}-01-01\" for year in range(2016, 2025)]\n",
"\n",
"for date in dates:\n",
" for element, name in zip(elements, names):\n",
" # Append to a dataframe: row = date, column = element, value = amount\n",
" new_row = {\"date\": date, \"element\": name, \"amount\": element(date)}\n",
" # Append row to the dataframe\n",
" df = pd.concat([df, pd.DataFrame([new_row])])\n",
"import pandas as pd\n",
"\n",
"rows = [\n",
" {\"date\": date, \"element\": name, \"amount\": element(date)}\n",
" for date in dates\n",
" for element, name in zip(elements, names)\n",
"]\n",
"df = pd.DataFrame(rows)\n",
"\n",
"# merge element cells\n",
"pivot_df = df.pivot(index=\"date\", columns=\"element\", values=\"amount\")\n",
"pivot_df.fillna(\"\")"
]
Expand Down Expand Up @@ -1349,7 +1340,7 @@
" yaxis_range=[0, 500],\n",
" yaxis_tickformat=\",.0f\",\n",
" yaxis_tickprefix=\"£\",\n",
" yaxis_title=\"Amount(£m)\",\n",
" yaxis_title=\"Amount (£/month)\",\n",
" xaxis_title=\"Year\",\n",
" legend_title=\"Element\",\n",
")\n",
Expand All @@ -1359,11 +1350,16 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": []
"source": [
"## References\n",
"\n",
"- [The Welfare Reform Act 2012](https://www.legislation.gov.uk/ukpga/2012/5/contents) — the primary statute creating Universal Credit.\n",
"- [The Universal Credit Regulations 2013 (SI 2013/376)](https://www.legislation.gov.uk/uksi/2013/376/contents) — the operational regulations.\n",
"- DWP, [Benefit and pension rates](https://www.gov.uk/government/publications/benefit-and-pension-rates-2025-to-2026) — annual rate uprating.\n",
"- 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."
]
}
],
"metadata": {
Expand All @@ -1388,4 +1384,4 @@
},
"nbformat": 4,
"nbformat_minor": 1
}
}