From 9832a7cfa2085ec886acb564d12b4be9536e0786 Mon Sep 17 00:00:00 2001 From: Vahid Ahmadi Date: Wed, 21 Jan 2026 13:26:28 +0000 Subject: [PATCH] Add Scotland UC households with youngest child under 1 calibration target Add calibration target for UC households in Scotland where the youngest child is aged 0 (under 1 year old). Data sourced from DWP Stat-Xplore UC Households dataset (November 2023): 13,992 households. This target helps calibrate the population eligible for the Scottish Child Payment baby boost. Co-Authored-By: Claude Opus 4.5 --- .github/workflows/pull_request.yaml | 2 +- changelog_entry.yaml | 4 ++ .../tests/test_scotland_uc_babies.py | 51 +++++++++++++++++++ policyengine_uk_data/utils/loss.py | 21 ++++++++ pyproject.toml | 2 +- 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 policyengine_uk_data/tests/test_scotland_uc_babies.py diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index e7be9e6f1..b66bd903c 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -24,7 +24,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install black + pip install black==25.1.0 - name: Check formatting run: black . -l 79 --check test: diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb..2630b84e1 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: minor + changes: + added: + - Add calibration target for UC households in Scotland with youngest child under 1 (~14k from DWP Stat-Xplore) diff --git a/policyengine_uk_data/tests/test_scotland_uc_babies.py b/policyengine_uk_data/tests/test_scotland_uc_babies.py new file mode 100644 index 000000000..b48d6151d --- /dev/null +++ b/policyengine_uk_data/tests/test_scotland_uc_babies.py @@ -0,0 +1,51 @@ +"""Test Scotland UC households with child under 1 calibration target. + +Source: DWP Stat-Xplore, UC Households dataset, November 2023 +https://stat-xplore.dwp.gov.uk/ +Filters: Scotland, Age of Youngest Child = 0 +Result: 13,992 households (~14k) +""" + +import pytest + + +@pytest.mark.xfail( + reason="Will pass after recalibration with new scotland_uc_households_child_under_1 target" +) +def test_scotland_uc_households_child_under_1(baseline): + """Test that UC households in Scotland with child under 1 matches DWP data. + + Target: ~14,000 households (13,992 from Stat-Xplore November 2023) + Source: DWP Stat-Xplore UC Households dataset + """ + region = baseline.calculate( + "region", map_to="household", period=2025 + ).values + uc = baseline.calculate("universal_credit", period=2025).values + household_weight = baseline.calculate( + "household_weight", map_to="household", period=2025 + ).values + + # Check if household has child under 1 + is_child = baseline.calculate( + "is_child", map_to="person", period=2025 + ).values + age = baseline.calculate("age", map_to="person", period=2025).values + + child_under_1 = is_child & (age < 1) + has_child_under_1 = ( + baseline.map_result(child_under_1, "person", "household") > 0 + ) + + scotland_uc_child_under_1 = ( + (region == "SCOTLAND") & (uc > 0) & has_child_under_1 + ) + total = (household_weight * scotland_uc_child_under_1).sum() + + TARGET = 14_000 # DWP Stat-Xplore November 2023: 13,992 rounded to 14k + TOLERANCE = 0.15 # 15% tolerance + + assert abs(total / TARGET - 1) < TOLERANCE, ( + f"Expected ~{TARGET/1000:.0f}k UC households with child under 1 in Scotland, " + f"got {total/1000:.0f}k ({total/TARGET*100:.0f}% of target)" + ) diff --git a/policyengine_uk_data/utils/loss.py b/policyengine_uk_data/utils/loss.py index fd0f55314..f31c98559 100644 --- a/policyengine_uk_data/utils/loss.py +++ b/policyengine_uk_data/utils/loss.py @@ -536,6 +536,27 @@ def pe_count(*variables): target_names.append("sss/scottish_child_payment") target_values.append(scp_target) + # UC households in Scotland with child under 1 + # Source: DWP Stat-Xplore, UC Households dataset, November 2023 + # https://stat-xplore.dwp.gov.uk/ + # Filters: Scotland, Age of Youngest Child = 0 + # ~14,000 households (13,992 in November 2023) + uc_amount = sim.calculate("universal_credit") + on_uc_family = uc_amount > 0 + on_uc_household = household_from_family(on_uc_family) > 0 + + child_under_1 = is_child & (age < 1) + has_child_under_1 = household_from_person(child_under_1) > 0 + + scotland_uc_child_under_1 = ( + (household_region == "SCOTLAND") & on_uc_household & has_child_under_1 + ) + df["dwp/scotland_uc_households_child_under_1"] = ( + scotland_uc_child_under_1.astype(float) + ) + target_names.append("dwp/scotland_uc_households_child_under_1") + target_values.append(14_000) # 13,992 rounded, November 2023 + # Council Tax band counts ct_data = pd.read_csv(STORAGE_FOLDER / "council_tax_bands_2024.csv") diff --git a/pyproject.toml b/pyproject.toml index 7f64dc4f5..725572fc5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ python_classes = ["Test*"] python_functions = ["test_*"] markers = [ "slow: marks tests as slow (deselect with '-m \"not slow\"')", - "unit: marks tests as unit tests", + "unit: marks tests as unit tests", "integration: marks tests as integration tests", ] filterwarnings = [