From 26b304395e182e56d8dcc61f09dc4f05fc6436be Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 5 Jun 2026 16:17:50 +0100 Subject: [PATCH 1/2] Impute mortgage and consumer debt from the Wealth and Assets Survey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds mortgage_debt (gross outstanding household mortgage, WAS HMortGR8) and consumer_debt (non-mortgage, non-student-loan borrowing) to the wealth imputation targets. These are the first liabilities the dataset carries, so a net wealth measure (total_wealth minus debt) can finally go negative for households whose debts exceed their assets, instead of bottoming out at a £0 point mass of asset-poor households. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../mortgage-consumer-debt-imputation.added.md | 1 + .../datasets/imputations/wealth.py | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 changelog.d/mortgage-consumer-debt-imputation.added.md diff --git a/changelog.d/mortgage-consumer-debt-imputation.added.md b/changelog.d/mortgage-consumer-debt-imputation.added.md new file mode 100644 index 00000000..10e5dadd --- /dev/null +++ b/changelog.d/mortgage-consumer-debt-imputation.added.md @@ -0,0 +1 @@ +Impute household `mortgage_debt` (gross outstanding mortgage debt, WAS `HMortGR8`) and `consumer_debt` (non-mortgage, non-student-loan borrowing) from the Wealth and Assets Survey, enabling a net wealth measure that can be negative for households whose debts exceed their assets. diff --git a/policyengine_uk_data/datasets/imputations/wealth.py b/policyengine_uk_data/datasets/imputations/wealth.py index 36c5fd4d..c80548a5 100644 --- a/policyengine_uk_data/datasets/imputations/wealth.py +++ b/policyengine_uk_data/datasets/imputations/wealth.py @@ -57,8 +57,17 @@ "savings", "num_vehicles", "student_loan_balance", + # Liabilities, so a net wealth measure can go negative for households whose + # debts exceed their assets. mortgage_debt is gross outstanding household + # mortgage debt (WAS HMortGR8); consumer_debt is non-mortgage, + # non-student-loan borrowing (personal loans, credit, hire purchase). + "mortgage_debt", + "consumer_debt", ] +# Imputed liabilities, clipped at zero on write (a debt cannot be negative). +DEBT_COLUMNS = {"mortgage_debt", "consumer_debt"} + WAS_RENAMES = { "R8xshhwgt": "household_weight", # Components for estimating land holdings. @@ -89,6 +98,7 @@ "DVLOSValR8_sum": "non_uk_land", "HFINWNTR8_Sum": "net_financial_wealth", "DVLUKDebtR8_sum": "uk_land_debt", + "HMortGR8": "mortgage_debt", # gross outstanding household mortgage debt "HFINWR8_SUM": "gross_financial_wealth", "TotalWlthR8": "wealth", "DVhvalueR8": "main_residence_value", @@ -153,6 +163,8 @@ def generate_was_table(was: pd.DataFrame): ] ].sum(axis=1) was["student_loan_balance"] = was["total_loans"] - was["total_loans_exc_slc"] + # Non-mortgage, non-student-loan borrowing (personal loans, credit, etc.). + was["consumer_debt"] = was["total_loans_exc_slc"] was["region"] = was["region"].map(REGIONS) return was @@ -347,7 +359,10 @@ def impute_wealth(dataset: UKSingleYearDataset) -> UKSingleYearDataset: person=dataset.person, ) continue - dataset.household[column] = output_df[column].values + values = output_df[column] + if column in DEBT_COLUMNS: + values = values.clip(lower=0) # a liability cannot be negative + dataset.household[column] = values.values dataset.validate() From fa7129a06a037bc10e91687c3a0166e5779e909b Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 5 Jun 2026 16:24:41 +0100 Subject: [PATCH 2/2] Make consumer_debt comprehensive (credit cards, overdrafts, HP) WAS does not itemise credit cards, overdrafts, hire purchase or arrears on the household file, so total_loans_exc_slc (formal loans only) captured barely a third of non-mortgage debt: GBP 1,138 across 11% of households. Define consumer_debt instead as the gap between gross financial wealth and financial wealth netted of all liabilities except student loans (HFINWR8 - HFINWNTR8_exSLC) - GBP 2,917 across 47% of households, covering all unsecured non-student debt. Co-Authored-By: Claude Opus 4.8 (1M context) --- policyengine_uk_data/datasets/imputations/wealth.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/policyengine_uk_data/datasets/imputations/wealth.py b/policyengine_uk_data/datasets/imputations/wealth.py index c80548a5..ca68e78d 100644 --- a/policyengine_uk_data/datasets/imputations/wealth.py +++ b/policyengine_uk_data/datasets/imputations/wealth.py @@ -97,6 +97,7 @@ # Other columns for reference. "DVLOSValR8_sum": "non_uk_land", "HFINWNTR8_Sum": "net_financial_wealth", + "HFINWNTR8_exSLC_Sum": "net_financial_wealth_exsl", # net of all debt but SLC "DVLUKDebtR8_sum": "uk_land_debt", "HMortGR8": "mortgage_debt", # gross outstanding household mortgage debt "HFINWR8_SUM": "gross_financial_wealth", @@ -163,8 +164,14 @@ def generate_was_table(was: pd.DataFrame): ] ].sum(axis=1) was["student_loan_balance"] = was["total_loans"] - was["total_loans_exc_slc"] - # Non-mortgage, non-student-loan borrowing (personal loans, credit, etc.). - was["consumer_debt"] = was["total_loans_exc_slc"] + # All non-mortgage, non-student-loan financial liabilities: personal and + # informal loans, credit and store cards, overdrafts, hire purchase, and + # arrears. WAS does not itemise these on the household file, but they are the + # gap between gross financial wealth and financial wealth netted of every + # liability except student loans. Captures far more than formal loans alone. + was["consumer_debt"] = ( + was["gross_financial_wealth"] - was["net_financial_wealth_exsl"] + ).clip(lower=0) was["region"] = was["region"].map(REGIONS) return was