diff --git a/changelog.d/745.md b/changelog.d/745.md new file mode 100644 index 000000000..2802f9d8f --- /dev/null +++ b/changelog.d/745.md @@ -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. diff --git a/docs/book/programs/gov/dwp/universal-credit.ipynb b/docs/book/programs/gov/dwp/universal-credit.ipynb index 08e1146d7..5581288a9 100644 --- a/docs/book/programs/gov/dwp/universal-credit.ipynb +++ b/docs/book/programs/gov/dwp/universal-credit.ipynb @@ -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", @@ -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, @@ -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(\"\")" ] @@ -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", @@ -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": { @@ -1388,4 +1384,4 @@ }, "nbformat": 4, "nbformat_minor": 1 -} +} \ No newline at end of file