Skip to content

Add age-based bus fare allocation and young-person fare reform#1781

Open
vahid-ahmadi wants to merge 5 commits into
mainfrom
bus-fare-age-allocation
Open

Add age-based bus fare allocation and young-person fare reform#1781
vahid-ahmadi wants to merge 5 commits into
mainfrom
bus-fare-age-allocation

Conversation

@vahid-ahmadi

Copy link
Copy Markdown
Collaborator

What

Adds the person/age allocation layer that lets PolicyEngine model age-targeted bus fare policies (e.g. Scotland-style free travel for under-22s), on top of the household bus_fare_spending input.

  • gov.dft.bus.fare_allocation_weight_by_age — provisional per-age weight for splitting household bus fares across members. NTS (England) bus-trip-by-age profile, adjusted for concessionary (free-pass) travel so it tracks fares paid, not trips. Clearly documented as a modelling allocation, not a fare-incidence estimate.
  • gov.dft.bus.young_person_fare.{age_limit, rate} — policy levers. Inert by default (age_limit = 0), so baseline is unchanged. A reform sets age_limit = 22 for free under-22 travel; rate (default 0 = free) supports discounts/flat fares too.
  • household_bus_fare_weight / person_bus_fare_spending — the allocation (household_fare × age_weight / household_total_weight), conserving the household total.
  • bus_fare_relief — government-funded fares for eligible young people. Routed through dft_subsidy_spending, which already feeds both household_benefits (→ net income) and gov_spending (→ Exchequer cost), so both sides of the policy are captured with no core surgery.

Why

bus_fare_spending is household-level (LCFS has no person-level fares), and rail is modelled at household level too. An age-targeted reform needs the fare attributed to people, which this provides — following existing PE-UK household→person allocation patterns (housing_benefit_assessable_capital, employer_ni_response_consumer_incidence).

Tests

test_bus_fare_age_allocation.py (3 passing): allocation splits by age weight and conserves the total; baseline relief is zero; an under-22 reform relieves the eligible member's allocated fare.

Caveats / scope

  • The age weights are provisional (two verified NTS anchors — 17–20 peak, ~25 mean — plus modelled mid-bands and assumed concessionary paid-shares; England used as a UK proxy). Fine for a directional prototype; publication-grade costing should use historical NTS0601 ODS or NTS microdata.
  • Static — no behavioural response (lower fares → more trips) yet.

Stacking

Stacked on #1780 (add-bus-fare-spending-variable) — it references bus_fare_spending. Merge #1780 first; this PR's base will retarget to main automatically. Also relies on the imputation in policyengine-uk-data#428.

🤖 Generated with Claude Code

vahid-ahmadi and others added 5 commits June 16, 2026 14:25
Companion to the LCFS bus fare imputation in policyengine-uk-data (#428).
Household-level COICOP 7.3.2 (bus & coach fares), mirroring petrol_spending/
diesel_spending. CPI-uprated; not added into the consumption total, which
already counts bus fares via transport_consumption. Provides the passenger
fare households pay (vs the ETB-based bus_subsidy_spending) for modelling
bus fare reforms.

Resolves #1779.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Allocate household bus_fare_spending across members by an NTS-derived,
concessionary-adjusted age weight (provisional), enabling age-targeted bus
fare reforms such as Scotland-style free travel for under-22s.

- gov.dft.bus.fare_allocation_weight_by_age: provisional per-age allocation weight
- gov.dft.bus.young_person_fare.{age_limit,rate}: policy levers (inert by default)
- household_bus_fare_weight, person_bus_fare_spending: the allocation
- bus_fare_relief: government-funded fares for eligible young people, routed
  through dft_subsidy_spending so it counts as both an in-kind household
  benefit and government spending

Depends on the bus_fare_spending input variable (#1780).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Base automatically changed from add-bus-fare-spending-variable to main June 17, 2026 11:13
@vahid-ahmadi vahid-ahmadi requested a review from MaxGhenis June 17, 2026 12:55
@vahid-ahmadi vahid-ahmadi self-assigned this Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant