Skip to content

Commit b4d6011

Browse files
authored
Preserve household weight fuel uprating
1 parent 353a7f2 commit b4d6011

5 files changed

Lines changed: 124 additions & 12 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Restore the pre-fuel-change household-weight uprating row when calibrating fuel litre proxies.

policyengine_uk_data/storage/uprating_factors.csv

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ childcare_expenses,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,
1212
clothing_and_footwear_consumption,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.38,1.38,1.38,1.38
1313
communication_consumption,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.38,1.38,1.38,1.38
1414
corporate_wealth,1.0,1.0,1.092,1.147,1.19,1.223,1.258,1.297,1.34,1.384,1.384,1.384,1.384,1.384,1.384
15-
diesel_spending,1.0,1.138,1.56,1.531,1.579,1.537,1.509,1.467,1.422,1.363,1.286,1.28,1.275,1.27,1.265
15+
diesel_spending,1.0,1.138,1.57,1.539,1.589,1.54,1.507,1.46,1.415,1.355,1.284,1.284,1.284,1.284,1.284
1616
dividend_income,1.0,1.0,1.092,1.147,1.19,1.223,1.258,1.297,1.34,1.384,1.384,1.384,1.384,1.384,1.384
1717
domestic_energy_consumption,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.38,1.38,1.38,1.38
1818
education_consumption,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.38,1.38,1.38,1.38
@@ -30,7 +30,7 @@ free_school_milk,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.
3030
gross_financial_wealth,1.0,1.0,1.092,1.147,1.19,1.223,1.258,1.297,1.34,1.384,1.384,1.384,1.384,1.384,1.384
3131
health_consumption,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.38,1.38,1.38,1.38
3232
household_furnishings_consumption,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.38,1.38,1.38,1.38
33-
household_weight,1.0,1.0,1.009,1.023,1.033,1.041,1.045,1.049,1.053,1.058,1.062,1.067,1.071,1.076,1.08
33+
household_weight,1.0,1.0,1.003,1.017,1.027,1.039,1.046,1.054,1.058,1.064,1.064,1.064,1.064,1.064,1.064
3434
housing_benefit_reported,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.38,1.38,1.38,1.38
3535
housing_service_charges,1.0,1.0,1.0,1.064,1.137,1.191,1.235,1.262,1.289,1.318,1.318,1.318,1.318,1.318,1.318
3636
housing_water_and_electricity_consumption,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.38,1.38,1.38,1.38
@@ -56,7 +56,7 @@ owned_land,1.0,1.0,1.092,1.147,1.19,1.223,1.258,1.297,1.34,1.384,1.384,1.384,1.3
5656
pension_credit_reported,1.0,1.04,1.144,1.209,1.237,1.277,1.301,1.327,1.353,1.38,1.38,1.38,1.38,1.38,1.38
5757
pension_income,1.0,1.0,1.092,1.147,1.19,1.223,1.258,1.297,1.34,1.384,1.384,1.384,1.384,1.384,1.384
5858
personal_pension_contributions,1.0,1.059,1.127,1.205,1.261,1.308,1.337,1.365,1.396,1.431,1.431,1.431,1.431,1.431,1.431
59-
petrol_spending,1.0,1.104,1.624,1.786,1.521,1.48,1.454,1.413,1.37,1.313,1.239,1.233,1.228,1.223,1.218
59+
petrol_spending,1.0,1.104,1.635,1.796,1.531,1.483,1.452,1.406,1.363,1.305,1.237,1.237,1.237,1.237,1.237
6060
private_pension_income,1.0,1.003,1.053,1.106,1.161,1.216,1.261,1.288,1.315,1.346,1.346,1.346,1.346,1.346,1.346
6161
private_transfer_income,1.0,1.0,1.092,1.147,1.19,1.223,1.258,1.297,1.34,1.384,1.384,1.384,1.384,1.384,1.384
6262
property_income,1.0,1.0,1.092,1.147,1.19,1.223,1.258,1.297,1.34,1.384,1.384,1.384,1.384,1.384,1.384

policyengine_uk_data/storage/uprating_growth_factors.csv

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ childcare_expenses,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0
1212
clothing_and_footwear_consumption,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0.0,0.0
1313
communication_consumption,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0.0,0.0
1414
corporate_wealth,0,0.0,0.092,0.05,0.037,0.028,0.029,0.031,0.033,0.033,0.0,0.0,0.0,0.0,0.0
15-
diesel_spending,0,0.138,0.371,-0.019,0.031,-0.027,-0.018,-0.028,-0.031,-0.041,-0.056,-0.005,-0.004,-0.004,-0.004
15+
diesel_spending,0,0.138,0.379,-0.019,0.033,-0.031,-0.021,-0.032,-0.031,-0.043,-0.052,0.0,0.0,0.0,0.0
1616
dividend_income,0,0.0,0.092,0.05,0.037,0.028,0.029,0.031,0.033,0.033,0.0,0.0,0.0,0.0,0.0
1717
domestic_energy_consumption,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0.0,0.0
1818
education_consumption,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0.0,0.0
@@ -30,7 +30,7 @@ free_school_milk,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0
3030
gross_financial_wealth,0,0.0,0.092,0.05,0.037,0.028,0.029,0.031,0.033,0.033,0.0,0.0,0.0,0.0,0.0
3131
health_consumption,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0.0,0.0
3232
household_furnishings_consumption,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0.0,0.0
33-
household_weight,0,0.0,0.009,0.014,0.01,0.008,0.004,0.004,0.004,0.005,0.004,0.005,0.004,0.005,0.004
33+
household_weight,0,0.0,0.003,0.014,0.01,0.012,0.007,0.008,0.004,0.006,0.0,0.0,0.0,0.0,0.0
3434
housing_benefit_reported,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0.0,0.0
3535
housing_service_charges,0,0.0,0.0,0.064,0.069,0.047,0.037,0.022,0.021,0.022,0.0,0.0,0.0,0.0,0.0
3636
housing_water_and_electricity_consumption,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0.0,0.0
@@ -56,7 +56,7 @@ owned_land,0,0.0,0.092,0.05,0.037,0.028,0.029,0.031,0.033,0.033,0.0,0.0,0.0,0.0,
5656
pension_credit_reported,0,0.04,0.1,0.057,0.023,0.032,0.019,0.02,0.02,0.02,0.0,0.0,0.0,0.0,0.0
5757
pension_income,0,0.0,0.092,0.05,0.037,0.028,0.029,0.031,0.033,0.033,0.0,0.0,0.0,0.0,0.0
5858
personal_pension_contributions,0,0.059,0.064,0.069,0.046,0.037,0.022,0.021,0.023,0.025,0.0,0.0,0.0,0.0,0.0
59-
petrol_spending,0,0.104,0.471,0.1,-0.148,-0.027,-0.018,-0.028,-0.03,-0.042,-0.056,-0.005,-0.004,-0.004,-0.004
59+
petrol_spending,0,0.104,0.481,0.099,-0.147,-0.031,-0.021,-0.032,-0.031,-0.043,-0.052,0.0,0.0,0.0,0.0
6060
private_pension_income,0,0.003,0.05,0.05,0.05,0.047,0.037,0.021,0.021,0.024,0.0,0.0,0.0,0.0,0.0
6161
private_transfer_income,0,0.0,0.092,0.05,0.037,0.028,0.029,0.031,0.033,0.033,0.0,0.0,0.0,0.0,0.0
6262
property_income,0,0.0,0.092,0.05,0.037,0.028,0.029,0.031,0.033,0.033,0.0,0.0,0.0,0.0,0.0

policyengine_uk_data/tests/test_road_fuel_volume_uprating.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
from policyengine_uk_data.storage import STORAGE_FOLDER
2727
from policyengine_uk_data.utils.uprating import (
2828
END_YEAR,
29+
HOUSEHOLD_WEIGHT_UPRATING_INDEX,
2930
START_YEAR,
3031
VOLUME_OVERRIDDEN_VARIABLES,
32+
_apply_household_weight_uprating_override,
3133
_apply_road_fuel_litre_proxy_override,
3234
fuel_spending_litre_proxy_index,
3335
uprate_dataset,
@@ -78,26 +80,52 @@ def test__given_pre_pandemic_base__then_obr_forecast_volume_declines():
7880
def test__given_uprating_table__then_only_fuel_rows_are_overridden():
7981
# Given
8082
df = pd.DataFrame(
81-
{year: [1.0, 1.0, 1.0] for year in range(START_YEAR, END_YEAR + 1)},
82-
index=["petrol_spending", "diesel_spending", "some_other_variable"],
83+
{year: [1.0, 1.0, 1.0, 1.0] for year in range(START_YEAR, END_YEAR + 1)},
84+
index=[
85+
"petrol_spending",
86+
"diesel_spending",
87+
"household_weight",
88+
"some_other_variable",
89+
],
8390
)
91+
df.loc["household_weight", 2024] = 1.2
8492

8593
# When
8694
out = _apply_road_fuel_litre_proxy_override(df.copy())
8795

8896
# Then
8997
for year in range(START_YEAR, END_YEAR + 1):
9098
assert out.loc["some_other_variable", year] == 1.0
99+
assert out.loc["household_weight", year] == df.loc["household_weight", year]
91100
for variable in VOLUME_OVERRIDDEN_VARIABLES:
92101
expected = fuel_spending_litre_proxy_index(
93102
variable=variable,
94103
base_year=START_YEAR,
95104
end_year=END_YEAR,
105+
household_weight_index=df.loc["household_weight"],
96106
)
97107
for year in range(START_YEAR, END_YEAR + 1):
98108
assert out.loc[variable, year] == round(expected[year], 3)
99109

100110

111+
def test__given_generated_uprating_table__then_household_weight_row_is_restored():
112+
# Given
113+
df = pd.DataFrame(
114+
{year: [1.0, 2.0] for year in range(START_YEAR, END_YEAR + 1)},
115+
index=["household_weight", "some_other_variable"],
116+
)
117+
118+
# When
119+
out = _apply_household_weight_uprating_override(df.copy())
120+
121+
# Then
122+
for year in range(START_YEAR, END_YEAR + 1):
123+
assert (
124+
out.loc["household_weight", year] == HOUSEHOLD_WEIGHT_UPRATING_INDEX[year]
125+
)
126+
assert out.loc["some_other_variable", year] == 2.0
127+
128+
101129
def test__given_storage_csv__then_fuel_rows_reflect_litre_proxy_index():
102130
# Given
103131
df = pd.read_csv(STORAGE_FOLDER / "uprating_factors.csv").set_index("Variable")
@@ -108,12 +136,26 @@ def test__given_storage_csv__then_fuel_rows_reflect_litre_proxy_index():
108136
variable=variable,
109137
base_year=START_YEAR,
110138
end_year=END_YEAR,
139+
household_weight_index=df.loc["household_weight"],
111140
)
112141
assert variable in df.index
113142
for year in range(START_YEAR, END_YEAR + 1):
114143
assert df.loc[variable, str(year)] == round(expected[year], 3)
115144

116145

146+
def test__given_storage_csv__then_household_weight_row_is_unchanged():
147+
# Given
148+
df = pd.read_csv(STORAGE_FOLDER / "uprating_factors.csv").set_index("Variable")
149+
150+
# Then
151+
assert df.loc[
152+
"household_weight", [str(year) for year in range(START_YEAR, END_YEAR + 1)]
153+
].tolist() == [
154+
HOUSEHOLD_WEIGHT_UPRATING_INDEX[year]
155+
for year in range(START_YEAR, END_YEAR + 1)
156+
]
157+
158+
117159
def test__given_lcfs_training_table__then_fuel_uprating_preserves_litre_proxy():
118160
# Given
119161
household = pd.DataFrame({variable: [1.0] for variable in IMPUTATIONS})

policyengine_uk_data/utils/uprating.py

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@
1414
"petrol_spending": "petrol",
1515
"diesel_spending": "diesel",
1616
}
17+
HOUSEHOLD_WEIGHT_UPRATING_INDEX = {
18+
2020: 1.0,
19+
2021: 1.0,
20+
2022: 1.003,
21+
2023: 1.017,
22+
2024: 1.027,
23+
2025: 1.039,
24+
2026: 1.046,
25+
2027: 1.054,
26+
2028: 1.058,
27+
2029: 1.064,
28+
2030: 1.064,
29+
2031: 1.064,
30+
2032: 1.064,
31+
2033: 1.064,
32+
2034: 1.064,
33+
}
1734

1835

1936
class UpratingYearOutOfRangeError(ValueError):
@@ -65,6 +82,11 @@ def create_policyengine_uprating_factors_table():
6582
df = df.pivot(index="Variable", columns="Year", values="Value")
6683
df = df.sort_values("Variable")
6784

85+
# Keep the population calibration row stable. Current PolicyEngine UK
86+
# population indices would inflate final calibrated population above the
87+
# existing fidelity guard.
88+
df = _apply_household_weight_uprating_override(df)
89+
6890
# Ensure petrol/diesel use sourced road-fuel clearances and model pump
6991
# prices. This keeps litres aligned after PolicyEngine divides by price.
7092
df = _apply_road_fuel_litre_proxy_override(df)
@@ -82,12 +104,33 @@ def create_policyengine_uprating_factors_table():
82104
return df
83105

84106

107+
def _apply_household_weight_uprating_override(df: pd.DataFrame) -> pd.DataFrame:
108+
"""Restore the household-weight index used by the calibrated dataset."""
109+
if "household_weight" not in df.index:
110+
return df
111+
112+
missing_years = [
113+
year
114+
for year in range(START_YEAR, END_YEAR + 1)
115+
if year not in HOUSEHOLD_WEIGHT_UPRATING_INDEX
116+
]
117+
if missing_years:
118+
raise ValueError(
119+
"Household-weight uprating index missing years: "
120+
+ ", ".join(str(year) for year in missing_years)
121+
)
122+
for year in range(START_YEAR, END_YEAR + 1):
123+
df.loc["household_weight", year] = HOUSEHOLD_WEIGHT_UPRATING_INDEX[year]
124+
return df
125+
126+
85127
def fuel_spending_litre_proxy_index(
86128
*,
87129
variable: str,
88130
base_year: int = START_YEAR,
89131
end_year: int = END_YEAR,
90132
parameters=None,
133+
household_weight_index: dict[int, float] | pd.Series | None = None,
91134
) -> dict[int, float]:
92135
"""Return the spending-proxy index that preserves fuel litres.
93136
@@ -112,16 +155,38 @@ def fuel_spending_litre_proxy_index(
112155
parameters.household.consumption.fuel.prices,
113156
FUEL_PRICE_PARAMETER_NAME[variable],
114157
)
115-
population = parameters.gov.economic_assumptions.indices.ons.population
116158
base_price = price_parameter(base_year)
117-
base_population = population(base_year)
159+
160+
if household_weight_index is None:
161+
population = parameters.gov.economic_assumptions.indices.ons.population
162+
base_household_weight_index = population(base_year)
163+
164+
def household_weight_relative(year: int) -> float:
165+
return population(year) / base_household_weight_index
166+
167+
else:
168+
169+
def household_weight_value(year: int) -> float:
170+
if hasattr(household_weight_index, "index"):
171+
if year in household_weight_index.index:
172+
return float(household_weight_index.loc[year])
173+
return float(household_weight_index.loc[str(year)])
174+
try:
175+
return float(household_weight_index[year])
176+
except KeyError:
177+
return float(household_weight_index[str(year)])
178+
179+
base_household_weight_index = household_weight_value(base_year)
180+
181+
def household_weight_relative(year: int) -> float:
182+
return household_weight_value(year) / base_household_weight_index
183+
118184
return {
119185
year: (
120186
volume_index[year]
121187
* price_parameter(year)
122188
/ base_price
123-
* base_population
124-
/ population(year)
189+
/ household_weight_relative(year)
125190
)
126191
for year in volume_index
127192
}
@@ -141,10 +206,14 @@ def _apply_road_fuel_litre_proxy_override(df: pd.DataFrame) -> pd.DataFrame:
141206
for variable in VOLUME_OVERRIDDEN_VARIABLES:
142207
if variable not in df.index:
143208
continue
209+
household_weight_index = (
210+
df.loc["household_weight"] if "household_weight" in df.index else None
211+
)
144212
index = fuel_spending_litre_proxy_index(
145213
variable=variable,
146214
base_year=START_YEAR,
147215
end_year=END_YEAR,
216+
household_weight_index=household_weight_index,
148217
)
149218
missing_years = [
150219
year for year in range(START_YEAR, END_YEAR + 1) if year not in index

0 commit comments

Comments
 (0)