From ed333e1714fa9ff3a4f09bc789e5aa37bca0bc8e Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 20 Feb 2025 09:04:26 +0000 Subject: [PATCH] refactored est no floors --- asset_list/AssetList.py | 27 +++++++++++++++++++++++++ etl/route_march_data_pull/app.py | 12 +++++------ recommendations/recommendation_utils.py | 7 +++++-- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/asset_list/AssetList.py b/asset_list/AssetList.py index 4ca4c2b8..74469c63 100644 --- a/asset_list/AssetList.py +++ b/asset_list/AssetList.py @@ -15,6 +15,12 @@ import asset_list.mappings.walls as walls_mappings import asset_list.mappings.heating_systems as heating_mappings import asset_list.mappings.exising_pv as existing_pv_mappings +from recommendations.recommendation_utils import ( + estimate_perimeter, + estimate_external_wall_area, + estimate_number_of_floors +) + logger = setup_logger() # OpenAI API Key (set this in your environment variables for security) @@ -224,6 +230,7 @@ class AssetList: "secondheat-description": "epc_secondary_heating", "transaction-type": "epc_reason", "energy-consumption-current": "epc_heat_demand", + "photo-supply": "epc_photo_supply" } FIND_EPC_DATA_NAMES = { "heating_text": "epc_estiamted_heating_kwh", @@ -274,6 +281,7 @@ class AssetList: # Attributes - these are columns that we produce, calcualted based on other pieces of data ATTRIBUTE_HAS_SOLAR = "attribute_has_solar" + ATTRIBUTE_NUMBER_OF_FLOORS = "attribute_est_number_floors" def __init__( self, @@ -645,3 +653,22 @@ class AssetList: self.standardised_asset_list[self.FIND_EPC_DATA_NAMES["Solar photovoltaics"]] | ~self.standardised_asset_list[self.EPC_API_DATA_NAMES["photo-supply"]].isin(["0.0", 0, None, ""]) ) + + accepted_epc_property_types = ["House", "Flat", "Bungalow", "Maisonette"] + + # The logic here is: + # 1) Take the property type provided by the HA themselves + # 2) In absence of that, take the EPC property type + # 3) Otherwise use None + self.standardised_asset_list[self.ATTRIBUTE_NUMBER_OF_FLOORS] = self.standardised_asset_list.apply( + lambda x: estimate_number_of_floors( + property_type=( + x[self.STANDARD_PROPERTY_TYPE].title() if + x[self.STANDARD_PROPERTY_TYPE].title() in accepted_epc_property_types else ( + x[self.EPC_API_DATA_NAMES["property-type"]] if not + pd.isnull(x[self.EPC_API_DATA_NAMES["property-type"]]) else None + ) + ) + ), + axis=1 + ) diff --git a/etl/route_march_data_pull/app.py b/etl/route_march_data_pull/app.py index 8b112ea2..9754e726 100644 --- a/etl/route_march_data_pull/app.py +++ b/etl/route_march_data_pull/app.py @@ -514,7 +514,6 @@ def app(): find_my_epc_data["Solar photovoltaics"] = False # Retrieve just the data we need - epc_df = epc_df[ [asset_list.DOMNA_PROPERTY_ID] + list(asset_list.EPC_API_DATA_NAMES.keys()) ].rename( @@ -529,15 +528,14 @@ def app(): ) asset_list.merge_data(epc_df) + # TODO: TEMP!!! + epc_df["epc_os_uprn"] = epc_df["epc_os_uprn"].astype("Int64").astype(str) + asset_list.standardised_asset_list = asset_list.standardised_asset_list.merge( + epc_df, how="left", left_on="ordnance_survey_uprn", right_on="epc_os_uprn" + ) asset_list.extract_attributes() - asset_list["Has Solar PV"] = asset_list["Has Solar PV"] | ~asset_list["photo-supply"].isin(["0.0", 0, None, ""]) - asset_list = asset_list.drop(columns=["photo-supply"]) - - # Rename the columns - asset_list = asset_list - asset_list["Estimated Number of Floors"] = asset_list.apply( lambda x: estimate_number_of_floors(property_type=x["Property Type"]) if not pd.isnull( x["Property Type"]) else None, axis=1 diff --git a/recommendations/recommendation_utils.py b/recommendations/recommendation_utils.py index 00da6107..602684cf 100644 --- a/recommendations/recommendation_utils.py +++ b/recommendations/recommendation_utils.py @@ -205,7 +205,7 @@ def get_wall_u_value( mapped_value = wall_uvalues_df[ wall_uvalues_df["Wall_type"] == mapped_description - ][age_band].values[0] + ][age_band].values[0] if pd.isnull(mapped_value) and "Park home" in mapped_description: # We don't know enough in this case so we default to 0 @@ -428,6 +428,9 @@ def estimate_number_of_floors(property_type): Using the property type, we estimate the number of floors in the property """ + if property_type is None: + return None + if property_type == "House": number_of_floors = 2 elif property_type in ["Flat", "Bungalow"]: @@ -560,7 +563,7 @@ def get_floor_u_value( insulation_lookup = s11[ s11["Age_band"].str.contains(age_band) & s11["Floor_construction"] == floor_type - ] + ] if insulation_lookup.empty: insulation_thickness = 0 else: