The UK tax-benefit model implements the United Kingdom’s tax and benefit system using PolicyEngine UK as the underlying calculation engine.
Entity structure¶
The UK model uses three entity levels:
household
└── benunit (benefit unit)
└── personPerson¶
Individual people with demographic and income characteristics.
Key variables:
age: Person’s age in yearsemployment_income: Annual employment incomeself_employment_income: Annual self-employment incomepension_income: Annual pension incomesavings_interest_income: Annual interest from savingsdividend_income: Annual dividend incomeincome_tax: Total income tax paidnational_insurance: Total NI contributionsis_disabled_for_benefits: Whether disabled for benefit purposes
Benunit (benefit unit)¶
The unit for benefit assessment. Usually a single person or a couple with dependent children.
Key variables:
universal_credit: Annual UC paymentchild_benefit: Annual child benefitworking_tax_credit: Annual WTC (legacy system)child_tax_credit: Annual CTC (legacy system)pension_credit: Annual pension creditincome_support: Annual income supporthousing_benefit: Annual housing benefitcouncil_tax_support: Annual council tax support
Important flags:
would_claim_uc: Must be True to claim UCwould_claim_WTC: Must be True to claim WTCwould_claim_CTC: Must be True to claim CTCwould_claim_IS: Must be True to claim ISwould_claim_pc: Must be True to claim pension creditwould_claim_child_benefit: Must be True to claim child benefitwould_claim_housing_benefit: Must be True to claim HB
Household¶
The residence unit, typically sharing accommodation.
Key variables:
household_net_income: Total household net incomehbai_household_net_income: HBAI-equivalised net incomehousehold_benefits: Total benefits receivedhousehold_tax: Total tax paidhousehold_market_income: Total market income
Required fields:
region: UK region (e.g., “LONDON”, “SOUTH_EAST”)tenure_type: Housing tenure (e.g., “RENT_PRIVATELY”, “OWNED_OUTRIGHT”)rent: Annual rent paidcouncil_tax: Annual council tax
Using the UK model¶
Loading representative data¶
from policyengine.tax_benefit_models.uk import PolicyEngineUKDataset
dataset = PolicyEngineUKDataset(
name="FRS 2023-24",
description="Family Resources Survey microdata",
filepath="./data/frs_2023_24_year_2026.h5",
year=2026,
)
print(f"People: {len(dataset.data.person):,}")
print(f"Benefit units: {len(dataset.data.benunit):,}")
print(f"Households: {len(dataset.data.household):,}")Creating custom scenarios¶
import pandas as pd
from microdf import MicroDataFrame
from policyengine.tax_benefit_models.uk import UKYearData
# Single parent with 2 children
person_df = MicroDataFrame(
pd.DataFrame({
"person_id": [0, 1, 2],
"person_benunit_id": [0, 0, 0],
"person_household_id": [0, 0, 0],
"age": [35, 8, 5],
"employment_income": [25000, 0, 0],
"person_weight": [1.0, 1.0, 1.0],
"is_disabled_for_benefits": [False, False, False],
"uc_limited_capability_for_WRA": [False, False, False],
}),
weights="person_weight"
)
benunit_df = MicroDataFrame(
pd.DataFrame({
"benunit_id": [0],
"benunit_weight": [1.0],
"would_claim_uc": [True],
"would_claim_child_benefit": [True],
"would_claim_WTC": [True],
"would_claim_CTC": [True],
}),
weights="benunit_weight"
)
household_df = MicroDataFrame(
pd.DataFrame({
"household_id": [0],
"household_weight": [1.0],
"region": ["LONDON"],
"rent": [15000], # £1,250/month
"council_tax": [2000],
"tenure_type": ["RENT_PRIVATELY"],
}),
weights="household_weight"
)
dataset = PolicyEngineUKDataset(
name="Single parent scenario",
description="One adult, two children",
filepath="./single_parent.h5",
year=2026,
data=UKYearData(
person=person_df,
benunit=benunit_df,
household=household_df,
)
)Running a simulation¶
from policyengine.core import Simulation
from policyengine.tax_benefit_models.uk import uk_latest
simulation = Simulation(
dataset=dataset,
tax_benefit_model_version=uk_latest,
)
simulation.run()
# Check results
output = simulation.output_dataset.data
print(output.household[["household_net_income", "household_benefits", "household_tax"]])Key parameters¶
Income tax¶
gov.hmrc.income_tax.allowances.personal_allowance.amount: Personal allowance (£12,570 in 2024-25)gov.hmrc.income_tax.rates.uk[0].rate: Basic rate (20%)gov.hmrc.income_tax.rates.uk[1].rate: Higher rate (40%)gov.hmrc.income_tax.rates.uk[2].rate: Additional rate (45%)gov.hmrc.income_tax.rates.uk[0].threshold: Basic rate threshold (£50,270)gov.hmrc.income_tax.rates.uk[1].threshold: Higher rate threshold (£125,140)
National insurance¶
gov.hmrc.national_insurance.class_1.main.primary_threshold: Primary threshold (£12,570)gov.hmrc.national_insurance.class_1.main.upper_earnings_limit: Upper earnings limit (£50,270)gov.hmrc.national_insurance.class_1.main.rate: Main rate (12% below UEL, 2% above)
Universal credit¶
gov.dwp.universal_credit.elements.standard_allowance.single_adult: Standard allowance for single adult (£334.91/month in 2024-25)gov.dwp.universal_credit.elements.child.first_child: First child element (£333.33/month)gov.dwp.universal_credit.elements.child.subsequent_child: Subsequent children (£287.92/month each)gov.dwp.universal_credit.means_test.reduction_rate: Taper rate (55%)gov.dwp.universal_credit.means_test.earned_income.disregard: Work allowance
Child benefit¶
gov.hmrc.child_benefit.rates.eldest_child: First child rate (£25.60/week)gov.hmrc.child_benefit.rates.additional_child: Additional children (£16.95/week each)gov.hmrc.child_benefit.income_tax_charge.threshold: HICBC threshold (£60,000)
Common policy reforms¶
Increasing personal allowance¶
from policyengine.core import Policy, Parameter, ParameterValue
import datetime
parameter = Parameter(
name="gov.hmrc.income_tax.allowances.personal_allowance.amount",
tax_benefit_model_version=uk_latest,
description="Personal allowance",
data_type=float,
)
policy = Policy(
name="Increase personal allowance to £15,000",
description="Raises personal allowance from £12,570 to £15,000",
parameter_values=[
ParameterValue(
parameter=parameter,
start_date=datetime.date(2026, 1, 1),
end_date=datetime.date(2026, 12, 31),
value=15000,
)
],
)Adjusting UC taper rate¶
parameter = Parameter(
name="gov.dwp.universal_credit.means_test.reduction_rate",
tax_benefit_model_version=uk_latest,
description="UC taper rate",
data_type=float,
)
policy = Policy(
name="Reduce UC taper to 50%",
description="Lowers taper rate from 55% to 50%",
parameter_values=[
ParameterValue(
parameter=parameter,
start_date=datetime.date(2026, 1, 1),
end_date=datetime.date(2026, 12, 31),
value=0.50, # 50%
)
],
)Abolishing two-child limit¶
# Set subsequent child element equal to first child
parameter = Parameter(
name="gov.dwp.universal_credit.elements.child.subsequent_child",
tax_benefit_model_version=uk_latest,
description="UC subsequent child element",
data_type=float,
)
policy = Policy(
name="Abolish two-child limit",
description="Sets subsequent child element equal to first child",
parameter_values=[
ParameterValue(
parameter=parameter,
start_date=datetime.date(2026, 1, 1),
end_date=datetime.date(2026, 12, 31),
value=333.33, # Match first child rate
)
],
)Regional variations¶
The UK model accounts for regional differences:
Council tax: Varies by local authority
Rent levels: Regional housing markets
Scottish income tax: Different rates and thresholds for Scottish taxpayers
Regions¶
Valid region values:
LONDONSOUTH_EASTSOUTH_WESTEAST_OF_ENGLANDWEST_MIDLANDSEAST_MIDLANDSYORKSHIRENORTH_WESTNORTH_EASTWALESSCOTLANDNORTHERN_IRELAND
Entity mapping¶
The UK model has a simpler entity structure than the US, with three levels: person → benunit → household.
Direct entity mapping¶
You can map data between entities using the map_to_entity method:
# Map person income to benunit level
benunit_income = dataset.data.map_to_entity(
source_entity="person",
target_entity="benunit",
columns=["employment_income"],
how="sum"
)
# Split household rent equally among persons
person_rent_share = dataset.data.map_to_entity(
source_entity="household",
target_entity="person",
columns=["rent"],
how="divide"
)
# Map benunit UC to household level
household_uc = dataset.data.map_to_entity(
source_entity="benunit",
target_entity="household",
columns=["universal_credit"],
how="sum"
)See the Entity mapping section in Core Concepts for full documentation on aggregation methods.
Data sources¶
The UK model can use several data sources:
Family Resources Survey (FRS): Official UK household survey
~19,000 households
Detailed income and benefit receipt
Published annually
Enhanced FRS: Uprated and enhanced version
Calibrated to population totals
Additional imputed variables
Multiple projection years
Custom datasets: User-created scenarios
Full control over household composition
Exact income levels
Specific benefit claiming patterns
Validation¶
When creating custom datasets, validate:
Would claim flags: All set to True
Disability flags: Set explicitly (not random)
Join keys: Person data links to benunits and households
Required fields: Region, tenure_type set correctly
Weights: Sum to expected values
Income ranges: Realistic values
Examples¶
See working examples in the examples/ directory:
employment_income_variation_uk.py: Vary employment income, analyse benefit phase-outspolicy_change_uk.py: Apply reforms, analyse winners/losersincome_bands_uk.py: Create income band scenarios
References¶
PolicyEngine UK documentation: https://
policyengine .github .io /policyengine -uk/ UK tax-benefit system: https://
www .gov .uk /browse /benefits HBAI methodology: https://
www .gov .uk /government /statistics /households -below -average -income -for -financial -years -ending -1995 -to -2023