mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
setting up the wall mapping functions
This commit is contained in:
parent
d1c20944af
commit
28e9f37739
8 changed files with 672 additions and 61 deletions
|
|
@ -59,24 +59,24 @@ def app():
|
|||
Property UPRN
|
||||
"""
|
||||
|
||||
data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Hackney"
|
||||
data_filename = "Domna SHF Wave 3 (3).xlsx"
|
||||
sheet_name = "Domna Wave 3"
|
||||
postcode_column = 'Postcode'
|
||||
address1_column = "Address 1"
|
||||
address1_method = None
|
||||
fulladdress_column = None
|
||||
address_cols_to_concat = ["Address 1"]
|
||||
data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/NCHA/20260129 SAL"
|
||||
data_filename = "NCHA ASSET LIST 1.xlsx"
|
||||
sheet_name = "NCHA ASSET LIST"
|
||||
postcode_column = 'POSTCODE'
|
||||
address1_column = None
|
||||
address1_method = "house_number_extraction"
|
||||
fulladdress_column = 'ADDRESS'
|
||||
address_cols_to_concat = []
|
||||
missing_postcodes_method = None
|
||||
landlord_year_built = "Construction Years"
|
||||
landlord_os_uprn = "UPRN"
|
||||
landlord_property_type = "Type"
|
||||
landlord_built_form = "Attachment"
|
||||
landlord_wall_construction = "Wall type"
|
||||
landlord_year_built = None
|
||||
landlord_os_uprn = None
|
||||
landlord_property_type = "PROPERTY TYPE"
|
||||
landlord_built_form = "BUILD FORM"
|
||||
landlord_wall_construction = "wall combined"
|
||||
landlord_roof_construction = None
|
||||
landlord_heating_system = None
|
||||
landlord_existing_pv = None
|
||||
landlord_property_id = "Row ID"
|
||||
landlord_property_id = "UPRN"
|
||||
landlord_sap = None
|
||||
outcomes_filename = None
|
||||
outcomes_sheetname = None
|
||||
|
|
|
|||
|
|
@ -427,6 +427,8 @@ PROPERTY_MAPPING = {
|
|||
'End Terrace': 'unknown',
|
||||
'Detached': 'unknown',
|
||||
'Mid-terrace': 'unknown',
|
||||
'MID - TERRACE': 'unknown'
|
||||
'MID - TERRACE': 'unknown',
|
||||
'COMOFF': 'unknown',
|
||||
'LOTS': 'unknown'
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,6 +354,15 @@ WALL_CONSTRUCTION_MAPPINGS = {
|
|||
'System built Internal': 'insulated system built',
|
||||
|
||||
'Cavity: AsBuilt (1976-1982), TimberFrame: AsBuilt': 'cavity unknown insulation',
|
||||
'Cavity: FilledCavityPlusExternal': 'filled cavity'
|
||||
'Cavity: FilledCavityPlusExternal': 'filled cavity',
|
||||
|
||||
'Cavity, Filled Cavity': 'filled cavity',
|
||||
'Solid Brick, As Built': 'solid brick unknown insulation',
|
||||
'Cavity, As Built': 'cavity unknown insulation',
|
||||
'Sandstone, As Built': 'sandstone or limestone unknown insulation',
|
||||
'Timber Frame, As Built': 'timber frame unknown insulation',
|
||||
'Solid Brick, Internal Insulation': 'insulated solid brick',
|
||||
'Granite or Whinstone, As Built': 'granite or whinstone unknown insulation',
|
||||
'Solid Brick, External': 'insulated solid brick'
|
||||
|
||||
}
|
||||
|
|
|
|||
0
backend/onboarders/base.py
Normal file
0
backend/onboarders/base.py
Normal file
247
backend/onboarders/epc_descriptions.py
Normal file
247
backend/onboarders/epc_descriptions.py
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
import re
|
||||
from enum import Enum
|
||||
from typing import Callable, Union, List
|
||||
|
||||
|
||||
class EpcConstructionAgeBand(Enum):
|
||||
before_1900: str = 'England and Wales: before 1900'
|
||||
from_1900_to_1929: str = 'England and Wales: 1900-1929'
|
||||
from_1930_to_1949: str = 'England and Wales: 1930-1949'
|
||||
from_1950_to_1966: str = 'England and Wales: 1950-1966'
|
||||
from_1967_to_1975: str = 'England and Wales: 1967-1975'
|
||||
from_1976_to_1982: str = 'England and Wales: 1976-1982'
|
||||
from_1983_to_1990: str = 'England and Wales: 1983-1990'
|
||||
from_1991_to_1995: str = 'England and Wales: 1991-1995'
|
||||
from_1996_to_2002: str = 'England and Wales: 1996-2002'
|
||||
from_2003_to_2006: str = 'England and Wales: 2003-2006'
|
||||
from_2007_to_2011: str = 'England and Wales: 2007-2011'
|
||||
from_2012_onwards: str = 'England and Wales: 2012-onwards'
|
||||
from_2012_to_2022: str = 'England and Wales: 2012-2022'
|
||||
from_2023_onwards: str = 'England and Wales: 2023 onwards'
|
||||
|
||||
def start_year(self) -> int:
|
||||
"""
|
||||
Extract the starting year of the age band.
|
||||
"""
|
||||
value = self.value.lower()
|
||||
|
||||
if 'before' in value:
|
||||
return 0
|
||||
match = re.search(r'(\d{4})', value)
|
||||
if not match:
|
||||
raise ValueError(f"Cannot determine start year from '{self.value}'")
|
||||
|
||||
return int(match.group(1))
|
||||
|
||||
@classmethod
|
||||
def from_year_onwards(cls, year: int) -> List["EpcConstructionAgeBand"]:
|
||||
"""
|
||||
Return all age bands whose starting year is >= the given year.
|
||||
"""
|
||||
return [
|
||||
band
|
||||
for band in cls
|
||||
if band.start_year() >= year
|
||||
]
|
||||
|
||||
|
||||
class EpcWallDescriptions(Enum):
|
||||
# Cavity wall descriptions
|
||||
cavity_insulated_assumed: str = "Cavity wall, as built, insulated (assumed)"
|
||||
cavity_partial_insulated_assumed: str = "Cavity wall, as built, partial insulation (assumed)"
|
||||
cavity_no_insulation_assumed: str = "Cavity wall, as built, no insulation (assumed)"
|
||||
cavity_filled_cavity: str = "Cavity wall, filled cavity"
|
||||
cavity_internal_insulation: str = "Cavity wall, with internal insulation"
|
||||
cavity_external_insulation: str = "Cavity wall, with external insulation"
|
||||
cavity_filled_plus_internal: str = "Cavity wall, filled cavity and internal insulation"
|
||||
cavity_filled_plus_external: str = "Cavity wall, filled cavity and external insulation"
|
||||
|
||||
# Solid wall descriptions
|
||||
solid_brick_internal_insulation: str = "Solid brick, with internal insulation"
|
||||
solid_brick_external_insulation: str = "Solid brick, with external insulation"
|
||||
solid_brick_no_insulation_assumed: str = 'Solid brick, as built, no insulation (assumed)'
|
||||
solid_brick_partial_insulated_assumed: str = 'Solid brick, as built, partial insulation (assumed)'
|
||||
solid_brick_insulated_assumed: str = 'Solid brick, as built, insulated (assumed)'
|
||||
|
||||
# System
|
||||
system_external_insulation: str = "System built, with external insulation"
|
||||
system_internal_insulation: str = "System built, with internal insulation"
|
||||
system_no_insulation_assumed: str = "System built, as built, no insulation (assumed)"
|
||||
system_partial_insulated_assumed: str = "System built, as built, partial insulation (assumed)"
|
||||
system_insulated_assumed: str = "System built, as built, insulated (assumed)"
|
||||
|
||||
# Timber
|
||||
timber_frame_internal_insulation: str = "Timber frame, with internal insulation"
|
||||
timber_frame_external_insulation: str = "Timber frame, with external insulation"
|
||||
timber_frame_no_insulation_assumed: str = "Timber frame, as built, no insulation (assumed)"
|
||||
timber_frame_partial_insulated_assumed: str = "Timber frame, as built, partial insulation (assumed)"
|
||||
timber_frame_insulated_assumed: str = "Timber frame, as built, insulated (assumed)"
|
||||
|
||||
# Granite/whinstone
|
||||
granite_whinstone_external_insulation: str = "Granite or whin, with external insulation"
|
||||
granite_whinstone_internal_insulation: str = "Granite or whin, with internal insulation"
|
||||
granite_whinstone_no_insulation_assumed: str = "Granite or whin, as built, no insulation (assumed)"
|
||||
granite_whinstone_partial_insulated_assumed: str = "Granite or whin, as built, partial insulation (assumed)"
|
||||
granite_whinestone_insulated_assumed: str = "Granite or whin, as built, insulated (assumed)"
|
||||
|
||||
# Sandstone/limestone
|
||||
sandstone_limestone_internal_insulation: str = "Sandstone, with internal insulation"
|
||||
sandstone_limestone_external_insulation: str = "Sandstone, with external insulation"
|
||||
sandstone_limestone_no_insulation_assumed: str = "Sandstone, as built, no insulation (assumed)"
|
||||
sandstone_limestone_partial_insulated_assumed: str = "Sandstone, as built, partial insulation (assumed)"
|
||||
sandstone_limestone_insulated_assumed: str = "Sandstone, as built, insulated (assumed)"
|
||||
|
||||
# Cob
|
||||
cob_as_built_average = "Cob, as built"
|
||||
cob_as_built_good = "Cob, as built"
|
||||
|
||||
|
||||
class EpcEfficiency(Enum):
|
||||
VERY_POOR = "Very Poor"
|
||||
POOR = "Poor"
|
||||
AVERAGE = "Average"
|
||||
GOOD = "Good"
|
||||
VERY_GOOD = "Very Good"
|
||||
NA = "N/A"
|
||||
|
||||
|
||||
EfficiencyRule = Union[
|
||||
EpcEfficiency,
|
||||
Callable[[EpcConstructionAgeBand], EpcEfficiency],
|
||||
]
|
||||
|
||||
|
||||
def cavity_filled_efficiency(age_band: EpcConstructionAgeBand) -> EpcEfficiency:
|
||||
""""
|
||||
Maps cavity filled to efficiency based on construction age band.
|
||||
:param age_band: EpcConstructionAgeBand
|
||||
:return: EpcEfficiency
|
||||
"""
|
||||
if age_band in {
|
||||
EpcConstructionAgeBand.from_2023_onwards
|
||||
}:
|
||||
return EpcEfficiency.VERY_GOOD
|
||||
|
||||
return EpcEfficiency.GOOD
|
||||
|
||||
|
||||
def internal_external_insulation_efficiency(
|
||||
age_band: EpcConstructionAgeBand,
|
||||
) -> EpcEfficiency:
|
||||
"""
|
||||
Maps:
|
||||
- cavity unfilled with internal/external insulation to efficiency based on construction age band. We assumed
|
||||
based on 100mm insulation
|
||||
- solid brick with internal/external insulation to efficiency based on construction age band. We assumed
|
||||
based on 100mm insulation
|
||||
- system built with internal/external insulation to efficiency based on construction age band. We assumed
|
||||
based on 100mm insulation
|
||||
|
||||
All of these wall types have the same behaviour in elmhurst
|
||||
:param age_band: EpcConstructionAgeBand
|
||||
:return: EpcEfficiency
|
||||
"""
|
||||
if age_band in {
|
||||
EpcConstructionAgeBand.from_1983_to_1990,
|
||||
EpcConstructionAgeBand.from_1991_to_1995,
|
||||
EpcConstructionAgeBand.from_1996_to_2002,
|
||||
EpcConstructionAgeBand.from_2003_to_2006,
|
||||
EpcConstructionAgeBand.from_2007_to_2011,
|
||||
EpcConstructionAgeBand.from_2012_to_2022,
|
||||
EpcConstructionAgeBand.from_2023_onwards,
|
||||
}:
|
||||
return EpcEfficiency.VERY_GOOD
|
||||
|
||||
return EpcEfficiency.GOOD
|
||||
|
||||
|
||||
def timber_granite_sandstone_internal_external_efficiency(age_band: EpcConstructionAgeBand) -> EpcEfficiency:
|
||||
""""
|
||||
Maps:
|
||||
- timber frame with internal/external wall insulation to efficiency based on construction age band.
|
||||
- sandstone/limestone with internal/external wall insulation to efficiency based on construction age band.
|
||||
- granite/whinstone with internal/external wall insulation to efficiency based on construction age band.
|
||||
:param age_band: EpcConstructionAgeBand
|
||||
:return: EpcEfficiency
|
||||
"""
|
||||
if age_band in {
|
||||
EpcConstructionAgeBand.from_2023_onwards
|
||||
}:
|
||||
return EpcEfficiency.VERY_GOOD
|
||||
|
||||
return EpcEfficiency.GOOD
|
||||
|
||||
|
||||
WALL_DESCRIPTION_METADATA = {
|
||||
# Note: all function mappings have been defined based on Elmhurst
|
||||
# Cavity
|
||||
# value mappings
|
||||
EpcWallDescriptions.cavity_no_insulation_assumed: EpcEfficiency.POOR,
|
||||
EpcWallDescriptions.cavity_partial_insulated_assumed: EpcEfficiency.AVERAGE,
|
||||
EpcWallDescriptions.cavity_insulated_assumed: EpcEfficiency.GOOD,
|
||||
EpcWallDescriptions.cavity_filled_plus_internal: EpcEfficiency.VERY_GOOD,
|
||||
EpcWallDescriptions.cavity_filled_plus_external: EpcEfficiency.VERY_GOOD,
|
||||
# function mappings
|
||||
EpcWallDescriptions.cavity_filled_cavity: cavity_filled_efficiency,
|
||||
EpcWallDescriptions.cavity_internal_insulation: internal_external_insulation_efficiency,
|
||||
EpcWallDescriptions.cavity_external_insulation: internal_external_insulation_efficiency,
|
||||
|
||||
# Solid brick
|
||||
# value mappings
|
||||
EpcWallDescriptions.solid_brick_no_insulation_assumed: EpcEfficiency.POOR,
|
||||
EpcWallDescriptions.solid_brick_partial_insulated_assumed: EpcEfficiency.AVERAGE,
|
||||
EpcWallDescriptions.solid_brick_insulated_assumed: EpcEfficiency.GOOD,
|
||||
# function mappings
|
||||
EpcWallDescriptions.solid_brick_internal_insulation: internal_external_insulation_efficiency,
|
||||
EpcWallDescriptions.solid_brick_external_insulation: internal_external_insulation_efficiency,
|
||||
|
||||
# System
|
||||
# value mappings
|
||||
EpcWallDescriptions.system_no_insulation_assumed: EpcEfficiency.POOR,
|
||||
EpcWallDescriptions.system_partial_insulated_assumed: EpcEfficiency.AVERAGE,
|
||||
EpcWallDescriptions.system_insulated_assumed: EpcEfficiency.GOOD,
|
||||
# function mappings
|
||||
EpcWallDescriptions.system_internal_insulation: internal_external_insulation_efficiency,
|
||||
EpcWallDescriptions.system_external_insulation: internal_external_insulation_efficiency,
|
||||
|
||||
# Timber frame
|
||||
# value mappings
|
||||
EpcWallDescriptions.timber_frame_no_insulation_assumed: EpcEfficiency.POOR,
|
||||
EpcWallDescriptions.timber_frame_partial_insulated_assumed: EpcEfficiency.AVERAGE,
|
||||
EpcWallDescriptions.timber_frame_insulated_assumed: EpcEfficiency.GOOD,
|
||||
# function mappings
|
||||
EpcWallDescriptions.timber_frame_internal_insulation: timber_granite_sandstone_internal_external_efficiency,
|
||||
EpcWallDescriptions.timber_frame_external_insulation: timber_granite_sandstone_internal_external_efficiency,
|
||||
|
||||
# Granite / whinstone
|
||||
EpcWallDescriptions.granite_whinstone_no_insulation_assumed: EpcEfficiency.VERY_POOR,
|
||||
EpcWallDescriptions.granite_whinstone_partial_insulated_assumed: EpcEfficiency.AVERAGE,
|
||||
EpcWallDescriptions.granite_whinestone_insulated_assumed: EpcEfficiency.GOOD,
|
||||
# function mappings
|
||||
EpcWallDescriptions.granite_whinstone_internal_insulation: timber_granite_sandstone_internal_external_efficiency,
|
||||
EpcWallDescriptions.granite_whinstone_external_insulation: timber_granite_sandstone_internal_external_efficiency,
|
||||
|
||||
# Sandstone / limestone
|
||||
EpcWallDescriptions.sandstone_limestone_no_insulation_assumed: EpcEfficiency.VERY_POOR,
|
||||
EpcWallDescriptions.sandstone_limestone_partial_insulated_assumed: EpcEfficiency.AVERAGE,
|
||||
EpcWallDescriptions.sandstone_limestone_insulated_assumed: EpcEfficiency.GOOD,
|
||||
# function mappings
|
||||
EpcWallDescriptions.sandstone_limestone_internal_insulation: timber_granite_sandstone_internal_external_efficiency,
|
||||
EpcWallDescriptions.sandstone_limestone_external_insulation: timber_granite_sandstone_internal_external_efficiency,
|
||||
|
||||
# Cob (special case)
|
||||
EpcWallDescriptions.cob_as_built_average: EpcEfficiency.AVERAGE,
|
||||
EpcWallDescriptions.cob_as_built_good: EpcEfficiency.GOOD,
|
||||
}
|
||||
|
||||
|
||||
def resolve_wall_efficiency(
|
||||
description: EpcWallDescriptions,
|
||||
age_band: EpcConstructionAgeBand,
|
||||
) -> EpcEfficiency:
|
||||
rule = WALL_DESCRIPTION_METADATA[description]
|
||||
|
||||
if isinstance(rule, EpcEfficiency):
|
||||
return rule
|
||||
|
||||
return rule(age_band)
|
||||
|
|
@ -1,14 +1,19 @@
|
|||
party_map = {
|
||||
"Before 1900": 'England and Wales: before 1900',
|
||||
"1900-1929": 'England and Wales: 1900-1929',
|
||||
"1930-1949": 'England and Wales: 1930-1949',
|
||||
"1950-1966": 'England and Wales: 1950-1966',
|
||||
"1967-1975": 'England and Wales: 1967-1975',
|
||||
"1976-1982": 'England and Wales: 1976-1982',
|
||||
"1983-1990": 'England and Wales: 1983-1990',
|
||||
"1991-1995": 'England and Wales: 1991-1995',
|
||||
"1996-2002": 'England and Wales: 1996-2002',
|
||||
"2003-2006": 'England and Wales: 2003-2006',
|
||||
"2007-2011": 'England and Wales: 2007-2011',
|
||||
"2012 onwards": 'England and Wales: 2012-2021',
|
||||
from backend.onboarders.epc_descriptions import EpcConstructionAgeBand
|
||||
|
||||
parity_map = {
|
||||
"Before 1900": EpcConstructionAgeBand.before_1900.value,
|
||||
"1900-1929": EpcConstructionAgeBand.from_1900_to_1929.value,
|
||||
"1930-1949": EpcConstructionAgeBand.from_1930_to_1949.value,
|
||||
"1950-1966": EpcConstructionAgeBand.from_1950_to_1966.value,
|
||||
"1967-1975": EpcConstructionAgeBand.from_1967_to_1975.value,
|
||||
"1976-1982": EpcConstructionAgeBand.from_1976_to_1982.value,
|
||||
"1983-1990": EpcConstructionAgeBand.from_1983_to_1990.value,
|
||||
"1991-1995": EpcConstructionAgeBand.from_1991_to_1995.value,
|
||||
"1996-2002": EpcConstructionAgeBand.from_1996_to_2002.value,
|
||||
"2003-2006": EpcConstructionAgeBand.from_2003_to_2006.value,
|
||||
"2007-2011": EpcConstructionAgeBand.from_2007_to_2011.value,
|
||||
"2012 onwards": EpcConstructionAgeBand.from_2012_onwards.value,
|
||||
# Newer age bands, under SAP10
|
||||
"2012-2022": EpcConstructionAgeBand.from_2012_to_2022.value,
|
||||
"2023 onwards": EpcConstructionAgeBand.from_2023_onwards.value,
|
||||
}
|
||||
|
|
|
|||
204
backend/onboarders/mappings/as_built_wall_classifiers.py
Normal file
204
backend/onboarders/mappings/as_built_wall_classifiers.py
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
def map_cavity_wall_insulation(age_band):
|
||||
if age_band in [
|
||||
'England and Wales: before 1900',
|
||||
'England and Wales: 1900-1929',
|
||||
'England and Wales: 1930-1949',
|
||||
'England and Wales: 1950-1966',
|
||||
'England and Wales: 1967-1975'
|
||||
]:
|
||||
return EpcWallDescriptions.cavity_no_insulation_assumed
|
||||
|
||||
if age_band in [
|
||||
'England and Wales: 1976-1982'
|
||||
]:
|
||||
return EpcWallDescriptions.cavity_partial_insulated_assumed
|
||||
|
||||
if age_band in [
|
||||
'England and Wales: 1983-1990',
|
||||
'England and Wales: 1991-1995',
|
||||
'England and Wales: 1996-2002',
|
||||
'England and Wales: 2003-2006',
|
||||
'England and Wales: 2007-2011',
|
||||
'England and Wales: 2012-2022',
|
||||
'England and Wales: 2023 onwards',
|
||||
]:
|
||||
return EpcWallDescriptions.cavity_insulated_assumed
|
||||
|
||||
raise NotImplementedError(f"Age band {age_band} not handled for cavity wall as built insulation mapping")
|
||||
|
||||
|
||||
def map_solid_wall_insulation(age_band):
|
||||
if age_band in [
|
||||
'England and Wales: before 1900', 'England and Wales: 1900-1929', 'England and Wales: 1930-1949',
|
||||
'England and Wales: 1967-1975'
|
||||
]:
|
||||
return EpcWallDescriptions.solid_brick_no_insulation_assumed
|
||||
|
||||
if age_band in [
|
||||
'England and Wales: 1976-1982'
|
||||
]:
|
||||
return EpcWallDescriptions.solid_brick_partial_insulated_assumed
|
||||
|
||||
if age_band in [
|
||||
'England and Wales: 1983-1990', 'England and Wales: 1991-1995', 'England and Wales: 1996-2002',
|
||||
'England and Wales: 2003-2006', 'England and Wales: 2007-2011', 'England and Wales: 2012-2022',
|
||||
'England and Wales: 2023 onwards',
|
||||
]:
|
||||
return EpcWallDescriptions.solid_brick_insulated_assumed
|
||||
|
||||
|
||||
def map_timber_frame_wall_insulation(age_band):
|
||||
# No insulation (Poor)
|
||||
if age_band in [
|
||||
'England and Wales: before 1900',
|
||||
'England and Wales: 1900-1929',
|
||||
'England and Wales: 1930-1949',
|
||||
]:
|
||||
return EpcWallDescriptions.timber_frame_no_insulation_assumed
|
||||
|
||||
# Partial insulation (Average)
|
||||
if age_band in [
|
||||
'England and Wales: 1950-1966',
|
||||
'England and Wales: 1967-1975',
|
||||
]:
|
||||
return EpcWallDescriptions.timber_frame_partial_insulated_assumed
|
||||
|
||||
# Insulated (Good)
|
||||
if age_band in [
|
||||
'England and Wales: 1976-1982',
|
||||
'England and Wales: 1983-1990',
|
||||
'England and Wales: 1991-1995',
|
||||
'England and Wales: 1996-2002',
|
||||
'England and Wales: 2003-2006',
|
||||
'England and Wales: 2007-2011',
|
||||
'England and Wales: 2012-2022',
|
||||
'England and Wales: 2023 onwards',
|
||||
]:
|
||||
return EpcWallDescriptions.timber_frame_insulated_assumed
|
||||
|
||||
# TODO: Unknown / pre-1930 handling
|
||||
raise NotImplementedError(f"Age band {age_band} not handled for timber frame wall insulation mapping")
|
||||
|
||||
|
||||
def map_system_build_wall_insulation(age_band):
|
||||
# No insulation (Poor)
|
||||
if age_band in [
|
||||
'England and Wales: before 1900',
|
||||
'England and Wales: 1900-1929',
|
||||
'England and Wales: 1930-1949',
|
||||
'England and Wales: 1950-1966',
|
||||
'England and Wales: 1967-1975',
|
||||
]:
|
||||
return EpcWallDescriptions.system_no_insulation_assumed
|
||||
|
||||
# Partial insulation (Average)
|
||||
if age_band in [
|
||||
'England and Wales: 1976-1982',
|
||||
]:
|
||||
return EpcWallDescriptions.system_partial_insulated_assumed
|
||||
|
||||
# Insulated (Good)
|
||||
if age_band in [
|
||||
'England and Wales: 1983-1990',
|
||||
'England and Wales: 1991-1995',
|
||||
'England and Wales: 1996-2002',
|
||||
'England and Wales: 2003-2006',
|
||||
'England and Wales: 2007-2011',
|
||||
'England and Wales: 2012-2022',
|
||||
'England and Wales: 2023 onwards',
|
||||
]:
|
||||
return EpcWallDescriptions.system_insulated_assumed
|
||||
|
||||
# TODO: Unknown / early system build handling
|
||||
raise NotImplementedError(f"Age band {age_band} not handled for system build wall insulation mapping")
|
||||
|
||||
|
||||
def map_granite_wall_insulation(age_band):
|
||||
# No insulation (Very Poor)
|
||||
if age_band in [
|
||||
'England and Wales: before 1900',
|
||||
'England and Wales: 1900-1929',
|
||||
'England and Wales: 1930-1949',
|
||||
'England and Wales: 1950-1966',
|
||||
'England and Wales: 1967-1975',
|
||||
]:
|
||||
return EpcWallDescriptions.granite_whinstone_no_insulation_assumed
|
||||
|
||||
# Partial insulation (Average)
|
||||
if age_band in [
|
||||
'England and Wales: 1976-1982',
|
||||
]:
|
||||
return EpcWallDescriptions.granite_whinstone_partial_insulated_assumed
|
||||
|
||||
# Insulated (Good)
|
||||
if age_band in [
|
||||
'England and Wales: 1983-1990',
|
||||
'England and Wales: 1991-1995',
|
||||
'England and Wales: 1996-2002',
|
||||
'England and Wales: 2003-2006',
|
||||
'England and Wales: 2007-2011',
|
||||
'England and Wales: 2012-2022',
|
||||
'England and Wales: 2023 onwards',
|
||||
]:
|
||||
return EpcWallDescriptions.granite_whinestone_insulated_assumed
|
||||
|
||||
raise NotImplementedError(f"Age band {age_band} not handled for granite wall insulation mapping")
|
||||
|
||||
|
||||
def map_sandstone_wall_insulation(age_band):
|
||||
# No insulation (Very Poor)
|
||||
if age_band in [
|
||||
'England and Wales: before 1900',
|
||||
'England and Wales: 1900-1929',
|
||||
'England and Wales: 1930-1949',
|
||||
'England and Wales: 1950-1966',
|
||||
'England and Wales: 1967-1975',
|
||||
]:
|
||||
return EpcWallDescriptions.sandstone_limestone_no_insulation_assumed
|
||||
|
||||
# Partial insulation (Average)
|
||||
if age_band in [
|
||||
'England and Wales: 1976-1982',
|
||||
]:
|
||||
return EpcWallDescriptions.sandstone_limestone_partial_insulated_assumed
|
||||
|
||||
# Insulated (Good)
|
||||
if age_band in [
|
||||
'England and Wales: 1983-1990',
|
||||
'England and Wales: 1991-1995',
|
||||
'England and Wales: 1996-2002',
|
||||
'England and Wales: 2003-2006',
|
||||
'England and Wales: 2007-2011',
|
||||
'England and Wales: 2012-2022',
|
||||
'England and Wales: 2023 onwards',
|
||||
]:
|
||||
return EpcWallDescriptions.sandstone_limestone_insulated_assumed
|
||||
|
||||
raise NotImplementedError(f"Age band {age_band} not handled for sandstone wall insulation mapping")
|
||||
|
||||
|
||||
def map_cob_wall_insulation(age_band):
|
||||
# Cob, as built (Average)
|
||||
if age_band in [
|
||||
'England and Wales: before 1900',
|
||||
'England and Wales: 1900-1929',
|
||||
'England and Wales: 1930-1949',
|
||||
'England and Wales: 1950-1966',
|
||||
'England and Wales: 1967-1975',
|
||||
'England and Wales: 1976-1982',
|
||||
]:
|
||||
return EpcWallDescriptions.cob_as_built_average
|
||||
|
||||
# Cob, as built (Good)
|
||||
if age_band in [
|
||||
'England and Wales: 1983-1990',
|
||||
'England and Wales: 1991-1995',
|
||||
'England and Wales: 1996-2002',
|
||||
'England and Wales: 2003-2006',
|
||||
'England and Wales: 2007-2011',
|
||||
'England and Wales: 2012-2022',
|
||||
'England and Wales: 2023 onwards',
|
||||
]:
|
||||
return EpcWallDescriptions.cob_as_built_good
|
||||
|
||||
raise NotImplementedError(f"Age band {age_band} not handled for cob wall insulation mapping")
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
import pandas as pd
|
||||
from etl.epc.DataProcessor import construction_age_bounds_map
|
||||
from backend.onboarders.mappings.property_type import parity_map as property_map
|
||||
from backend.onboarders.mappings.age_band import party_map as age_band_map
|
||||
from backend.onboarders.mappings.age_band import parity_map as age_band_map
|
||||
from backend.onboarders.mappings.built_form import parity_map as built_form_map
|
||||
from onboarders.epc_descriptions import EpcWallDescriptions, EpcConstructionAgeBand
|
||||
|
||||
|
||||
def check_nulls(data, original_column, mapped_column):
|
||||
|
|
@ -17,7 +18,6 @@ def check_nulls(data, original_column, mapped_column):
|
|||
|
||||
|
||||
# Sample input data
|
||||
|
||||
data = pd.read_excel(
|
||||
"/Users/khalimconn-kowlessar/Documents/hestia/Customers/Peabody/Nov 2025 Consulting Project/2025_11_11 - Peabody "
|
||||
"- Data Extracts for Domna.xlsx",
|
||||
|
|
@ -30,18 +30,6 @@ data = pd.read_excel(
|
|||
# 3) Indicate already installed measures
|
||||
|
||||
# ------------ construction_age_band ------------
|
||||
# Map to EPC age bands
|
||||
# def construction_date_to_band(year):
|
||||
# if pd.isnull(year):
|
||||
# return None
|
||||
# # Get the year from the date which is numpy datetime format
|
||||
# for label, ranges in construction_age_bounds_map.items():
|
||||
# if ranges["l"] <= year <= ranges["u"]:
|
||||
# return label
|
||||
# raise NotImplementedError("year out of bounds")
|
||||
#
|
||||
#
|
||||
# data["construction_age_band"] = pd.to_datetime(data["Construction Date"]).dt.year.apply(construction_date_to_band)
|
||||
|
||||
data["construction_age_band"] = data["Construction Years"].map(age_band_map)
|
||||
|
||||
|
|
@ -59,30 +47,186 @@ assert pd.isnull(data["built_form"]).sum() == 0, "Some built forms were not mapp
|
|||
|
||||
# ------------ Wall Construction ------------
|
||||
|
||||
data["walls_combined"] = data["Wall Construction"] + "+" + data["Wall Insulation"].fillna("Unknown Insulation")
|
||||
|
||||
data["Wall Insulation"].value_counts()
|
||||
data["Wall Construction"].value_counts()
|
||||
# Unique combindations
|
||||
wall_mapping = {
|
||||
# Cavity walls
|
||||
('Cavity', 'FilledCavity'): EpcWallDescriptions.cavity_filled_cavity.value,
|
||||
('Cavity', 'Internal'): EpcWallDescriptions.cavity_internal_insulation.value,
|
||||
('Cavity', 'External'): EpcWallDescriptions.cavity_external_insulation.value,
|
||||
('Cavity', 'FilledCavityPlusInternal'): EpcWallDescriptions.cavity_filled_plus_internal.value,
|
||||
('Cavity', 'FilledCavityPlusExternal'): EpcWallDescriptions.cavity_filled_plus_external.value,
|
||||
('Cavity', 'AsBuilt'): None, # To be classified
|
||||
('Cavity', 'Unknown'): None, # To be classified
|
||||
|
||||
as_built_map = {
|
||||
"Cavity": {"insulated_age_bands": [], "partial_insulated_age_bands": []},
|
||||
"Solid Brick": {"insulated_age_bands": [], "partial_insulated_age_bands": []},
|
||||
"System": {"insulated_age_bands": [], "partial_insulated_age_bands": []},
|
||||
"Timber Frame": {"insulated_age_bands": [], "partial_insulated_age_bands": []},
|
||||
"Sandstone": {"insulated_age_bands": [], "partial_insulated_age_bands": []},
|
||||
"Granite": {"insulated_age_bands": [], "partial_insulated_age_bands": []},
|
||||
"Cob": {"insulated_age_bands": [], "partial_insulated_age_bands": []},
|
||||
# System built walls
|
||||
('System', 'External'): EpcWallDescriptions.system_external_insulation.value,
|
||||
('System', 'Internal'): EpcWallDescriptions.system_internal_insulation.value,
|
||||
('System', 'AsBuilt'): None, # To be classified
|
||||
('System', 'Unknown'): None,
|
||||
|
||||
# Timber Frame walls
|
||||
('Timber Frame', 'Internal'): EpcWallDescriptions.timber_frame_internal_insulation.value,
|
||||
('Timber Frame', 'External'): EpcWallDescriptions.timber_frame_external_insulation.value,
|
||||
('Timber Frame', 'AsBuilt'): None, # To be classified
|
||||
('Timber Frame', 'Unknown'): None,
|
||||
|
||||
# Solid Brick walls
|
||||
('Solid Brick', 'External'): EpcWallDescriptions.solid_brick_external_insulation.value,
|
||||
('Solid Brick', 'Internal'): EpcWallDescriptions.solid_brick_internal_insulation.value,
|
||||
('Solid Brick', 'AsBuilt'): None, # To be classified
|
||||
('Solid Brick', 'Unknown'): None,
|
||||
|
||||
# Granite walls
|
||||
('Granite', 'External'): EpcWallDescriptions.granite_whinstone_external_insulation.value,
|
||||
("Granite", 'Internal'): EpcWallDescriptions.granite_whinstone_internal_insulation.value,
|
||||
('Granite', 'AsBuilt'): None,
|
||||
('Granite', 'Unknown'): None,
|
||||
|
||||
# Sandstone walls
|
||||
('Sandstone', 'Internal'): EpcWallDescriptions.sandstone_limestone_internal_insulation.value,
|
||||
('Sandstone', 'External'): EpcWallDescriptions.sandstone_limestone_external_insulation.value,
|
||||
('Sandstone', 'Unknown'): None,
|
||||
('Sandstone', 'AsBuilt'): None,
|
||||
|
||||
# Cob walls
|
||||
('Cob', 'AsBuilt'): None,
|
||||
}
|
||||
|
||||
|
||||
def map_wall_construction(wall_constuction, wall_insulation, construction_age_band):
|
||||
if wall_insulation == "AsBuilt":
|
||||
# Deduce based on wall construction and age band
|
||||
bands = as_built_map.get(wall_constuction, None)
|
||||
if bands is None:
|
||||
raise NotImplementedError(f"Wall construction {wall_constuction} not in as built map")
|
||||
def map_cavity_wall_insulation(age_band: EpcConstructionAgeBand):
|
||||
if age_band.start_year() < 1976:
|
||||
return EpcWallDescriptions.cavity_no_insulation_assumed
|
||||
|
||||
# We check if the age band is in insulated or partial insulated, and if neither, we assume uninsulated
|
||||
if age_band == EpcConstructionAgeBand.from_1976_to_1982:
|
||||
return EpcWallDescriptions.cavity_partial_insulated_assumed
|
||||
|
||||
if age_band in EpcConstructionAgeBand.from_year_onwards(1983):
|
||||
return EpcWallDescriptions.cavity_insulated_assumed
|
||||
|
||||
raise NotImplementedError(f"Age band {age_band} not handled for cavity wall as built insulation mapping")
|
||||
|
||||
|
||||
def map_solid_wall_insulation(age_band: EpcConstructionAgeBand):
|
||||
if age_band.start_year() < 1976:
|
||||
return EpcWallDescriptions.solid_brick_no_insulation_assumed
|
||||
|
||||
if age_band == EpcConstructionAgeBand.from_1976_to_1982:
|
||||
return EpcWallDescriptions.solid_brick_partial_insulated_assumed
|
||||
|
||||
if age_band in EpcConstructionAgeBand.from_year_onwards(1983):
|
||||
return EpcWallDescriptions.solid_brick_insulated_assumed
|
||||
|
||||
raise NotImplementedError(
|
||||
f"Age band {age_band.value} not handled for solid wall insulation mapping"
|
||||
)
|
||||
|
||||
|
||||
def map_timber_frame_wall_insulation(age_band: EpcConstructionAgeBand):
|
||||
if age_band.start_year() < 1950:
|
||||
return EpcWallDescriptions.timber_frame_no_insulation_assumed
|
||||
|
||||
if age_band.start_year() < 1976:
|
||||
return EpcWallDescriptions.timber_frame_partial_insulated_assumed
|
||||
|
||||
if age_band in EpcConstructionAgeBand.from_year_onwards(1976):
|
||||
return EpcWallDescriptions.timber_frame_insulated_assumed
|
||||
|
||||
raise NotImplementedError(
|
||||
f"Age band {age_band.value} not handled for timber frame wall insulation mapping"
|
||||
)
|
||||
|
||||
|
||||
def map_system_build_wall_insulation(age_band: EpcConstructionAgeBand):
|
||||
if age_band.start_year() < 1976:
|
||||
return EpcWallDescriptions.system_no_insulation_assumed
|
||||
|
||||
if age_band == EpcConstructionAgeBand.from_1976_to_1982:
|
||||
return EpcWallDescriptions.system_partial_insulated_assumed
|
||||
|
||||
if age_band in EpcConstructionAgeBand.from_year_onwards(1983):
|
||||
return EpcWallDescriptions.system_insulated_assumed
|
||||
|
||||
raise NotImplementedError(
|
||||
f"Age band {age_band.value} not handled for system build wall insulation mapping"
|
||||
)
|
||||
|
||||
|
||||
def map_granite_wall_insulation(age_band: EpcConstructionAgeBand):
|
||||
if age_band.start_year() < 1976:
|
||||
return EpcWallDescriptions.granite_whinstone_no_insulation_assumed
|
||||
|
||||
if age_band == EpcConstructionAgeBand.from_1976_to_1982:
|
||||
return EpcWallDescriptions.granite_whinstone_partial_insulated_assumed
|
||||
|
||||
if age_band in EpcConstructionAgeBand.from_year_onwards(1983):
|
||||
return EpcWallDescriptions.granite_whinestone_insulated_assumed
|
||||
|
||||
raise NotImplementedError(
|
||||
f"Age band {age_band.value} not handled for granite wall insulation mapping"
|
||||
)
|
||||
|
||||
|
||||
def map_sandstone_wall_insulation(age_band: EpcConstructionAgeBand):
|
||||
if age_band.start_year() < 1976:
|
||||
return EpcWallDescriptions.sandstone_limestone_no_insulation_assumed
|
||||
|
||||
if age_band == EpcConstructionAgeBand.from_1976_to_1982:
|
||||
return EpcWallDescriptions.sandstone_limestone_partial_insulated_assumed
|
||||
|
||||
if age_band in EpcConstructionAgeBand.from_year_onwards(1983):
|
||||
return EpcWallDescriptions.sandstone_limestone_insulated_assumed
|
||||
|
||||
raise NotImplementedError(
|
||||
f"Age band {age_band.value} not handled for sandstone wall insulation mapping"
|
||||
)
|
||||
|
||||
|
||||
def map_cob_wall_insulation(age_band: EpcConstructionAgeBand):
|
||||
if age_band.start_year() < 1983:
|
||||
return EpcWallDescriptions.cob_as_built_average
|
||||
|
||||
if age_band in EpcConstructionAgeBand.from_year_onwards(1983):
|
||||
return EpcWallDescriptions.cob_as_built_good
|
||||
|
||||
raise NotImplementedError(
|
||||
f"Age band {age_band.value} not handled for cob wall insulation mapping"
|
||||
)
|
||||
|
||||
|
||||
AS_BUILT_WALL_CLASSIFIERS = {
|
||||
"Cavity": map_cavity_wall_insulation,
|
||||
"Solid Brick": map_solid_wall_insulation,
|
||||
"Timber Frame": map_timber_frame_wall_insulation,
|
||||
"System": map_system_build_wall_insulation,
|
||||
"Granite": map_granite_wall_insulation,
|
||||
"Sandstone": map_sandstone_wall_insulation,
|
||||
"Cob": map_cob_wall_insulation,
|
||||
}
|
||||
|
||||
data["landlord_wall_description"] = (
|
||||
data[["Wall Construction", "Wall Insulation"]]
|
||||
.apply(tuple, axis=1)
|
||||
.map(wall_mapping)
|
||||
)
|
||||
|
||||
|
||||
def fill_as_built(row):
|
||||
if row.landlord_wall_description is not None:
|
||||
return row.landlord_wall_description
|
||||
|
||||
classifier = AS_BUILT_WALL_CLASSIFIERS.get(row["Wall Construction"])
|
||||
if classifier is None:
|
||||
return None
|
||||
|
||||
return classifier(row.construction_age_band)
|
||||
|
||||
|
||||
data["landlord_wall_description"] = data.apply(fill_as_built, axis=1)
|
||||
|
||||
for _, x in data.iterrows():
|
||||
if x["construction_age_band"] == "England and Wales: 2012-2021":
|
||||
de
|
||||
|
||||
# Variables we want to map
|
||||
# 'Org Ref', 'Address 1', 'Address 2', 'Address 3', 'Postcode', 'Type',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue