debugging innovation uplift

This commit is contained in:
Khalim Conn-Kowlessar 2025-08-09 17:04:07 +01:00
parent a55d2902ce
commit a9018a541e
6 changed files with 109 additions and 12 deletions

2
.idea/Model.iml generated
View file

@ -7,7 +7,7 @@
<sourceFolder url="file://$MODULE_DIR$/open_uprn" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/recommendations" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="Fastapi-backend" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="AssetList" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

2
.idea/misc.xml generated
View file

@ -3,7 +3,7 @@
<component name="Black">
<option name="sdkName" value="Python 3.10 (backend)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Fastapi-backend" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="AssetList" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" />
</component>

View file

@ -860,7 +860,7 @@ class AssetList:
return date_str.year
# Handle numeric year (float or int)
if isinstance(date_str, (int, float)):
if isinstance(date_str, (int, float, np.int_)):
if 1000 <= int(date_str) <= 2100:
return int(date_str)
@ -887,9 +887,6 @@ class AssetList:
self.landlord_year_built
].apply(extract_year)
for x in self.standardised_asset_list[self.landlord_year_built].values:
extract_year(x)
# We now create standard lookups
to_remap = {
self.landlord_property_type: {
@ -1346,7 +1343,9 @@ class AssetList:
if self.new_format_non_insturives_present_v2:
existing_solar_non_intrusives_check = (
self.standardised_asset_list["non-intrusives: ROOF ORIENTATION"] == "ALREADY HAS SOLAR PV"
self.standardised_asset_list["non-intrusives: ROOF ORIENTATION"].str.strip().isin(
["ALREADY HAS SOLAR PV"]
)
)
else:
existing_solar_non_intrusives_check = (

View file

@ -58,6 +58,40 @@ def app():
EPC recommendations
Property UPRN
"""
# Abri
data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Abri/Post Inspections"
data_filename = "Desktop ABRI data - Standardised After Programmes (2).xlsx"
sheet_name = "Reviewed List"
postcode_column = 'domna_postcode'
address1_column = "domna_address_1"
address1_method = None
fulladdress_column = "domna_full_address"
address_cols_to_concat = []
missing_postcodes_method = None
landlord_year_built = "landlord_year_built"
landlord_os_uprn = None
landlord_property_type = "PropertyType_original_from_landlord"
landlord_built_form = "BuildForm_original_from_landlord"
landlord_wall_construction = "Wall Construction_original_from_landlord"
landlord_roof_construction = None
landlord_heating_system = "HeatingType_original_from_landlord"
landlord_existing_pv = None
landlord_property_id = "landlord_property_id"
landlord_sap = None
outcomes_filename = None
outcomes_sheetname = None
outcomes_postcode = None
outcomes_houseno = None
outcomes_id = None
outcomes_address = None
master_filepaths = []
master_id_colnames = []
master_to_asset_list_filepath = None
phase = False
ecosurv_landlords = None
asset_list_header = 0
landlord_block_reference = None
# Freebridge
data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Freebridge"
data_filename = "Domna - FCH property data May 25 copy.xlsx"

View file

@ -38,6 +38,12 @@ class Funding:
self.floor_area_band = None
self.project_scores_matrix = project_scores_matrix
self.partial_project_scores_matrix = partial_project_scores_matrix
# Filter on the starting band and floor area so we only do this once
self.partial_project_scores_matrix = self.partial_project_scores_matrix[
(self.partial_project_scores_matrix["Total Floor Area Band"] == self.floor_area_band) &
(self.partial_project_scores_matrix["Starting Band"] == self.starting_sap_band)
]
self.whlg_eligible_postcodes = whlg_eligible_postcodes
self.eco4_eligible = False
@ -432,10 +438,7 @@ class Funding:
"""
Calculate the partial project ABS score for a single measure.
"""
df = self.partial_project_scores_matrix[
(self.partial_project_scores_matrix["Total Floor Area Band"] == self.floor_area_band) &
(self.partial_project_scores_matrix["Starting Band"] == self.starting_sap_band)
]
df = self.partial_project_scores_matrix
if measure_type == "internal_wall_insulation":
if current_wall_uvalue is None:
@ -518,8 +521,10 @@ class Funding:
pre_heating_system = self._map_to_pre_main_heating(mainheating, main_fuel, mainheat_energy_eff)
pps = df[
(df["Pre_Main_Heating_Source"] == pre_heating_system) &
(df["Post_Main_Heating_Source"] == "Air to Water ASHP")
(df["Post_Main_Heating_Source"] == "Air to Water ASHP") &
(df["Measure_Type"] == "B_Upgrade_nopreHCs") # We assume we'll be making a heating system upgrade
]
if pps.shape[0] != 1:
raise ValueError("something went wrong, more than one pps for ashp")
return pps.squeeze()["Cost Savings"]

View file

@ -988,3 +988,62 @@ def test_uplift(
main_fuel=main_fuel,
mainheat_energy_eff=mainheat_energy_eff,
)
# Large scale testing for various measures
measures = [
{"type": "solar_pv", "is_innovation": True, "uplift": 0.45},
{"type": "internal_wall_insulation", "is_innovation": False, "uplift": 0},
{"type": "loft_insulation", "is_innovation": False, "uplift": 0},
{"type": "air_source_heat_pump", "is_innovation": False, "uplift": 0},
{"type": "cavity_wall_insulation", "is_innovation": True, "uplift": 0.25},
{"type": "high_heat_retention_storage_heaters", "is_innovation": False, "uplift": 0},
]
epc_df = pd.read_csv(
"/Users/khalimconn-kowlessar/Downloads/domestic-E08000025-Birmingham/certificates.csv"
)
from tqdm import tqdm
from etl.epc_clean.epc_attributes.MainheatAttributes import MainHeatAttributes
from etl.epc_clean.epc_attributes.MainFuelAttributes import MainFuelAttributes
mock_project_scores_matrix = mock_project_scores_matrix()
mock_whlg_postcodes = mock_whlg_postcodes()
mock_partial_scores_matrix = mock_partial_scores_matrix()
for _, x in tqdm(epc_df.iterrows(), total=len(epc_df)):
# inputs
mainheat_energy_eff = x["MAINHEAT_ENERGY_EFF"]
heating_cleaner = MainHeatAttributes(description=x["MAINHEAT_DESCRIPTION"])
fuel_cleaner = MainFuelAttributes(description=x["MAIN_FUEL"])
h = heating_cleaner.process()
f = fuel_cleaner.process()
funding = Funding(
project_scores_matrix=mock_project_scores_matrix,
partial_project_scores_matrix=mock_partial_scores_matrix,
whlg_eligible_postcodes=mock_whlg_postcodes,
social_cavity_abs_rate=13.5,
social_solid_abs_rate=17,
private_cavity_abs_rate=13.5,
private_solid_abs_rate=17,
tenure="Social"
)
funding.check_funding(
measures=measures,
starting_sap=33,
ending_sap=69,
floor_area=71,
mainheat_description=x["MAINHEAT_DESCRIPTION"],
heating_control_description=x["MAINHEATCONT_DESCRIPTION"],
is_cavity=True,
current_wall_uvalue=2,
is_partial=False,
existing_li_thickness=0,
has_wall_insulation_recommendation=True,
has_roof_insulation_recommendation=True,
mainheating=h,
main_fuel=f,
mainheat_energy_eff=mainheat_energy_eff,
)