From 03ca16bfc5c94d8325f5c20e5a82aabbb66e014d Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Fri, 26 Apr 2024 14:06:48 +0100 Subject: [PATCH] Added rightmove property valuation increase estimates --- .idea/Model.iml | 2 +- .idea/misc.xml | 2 +- backend/app/plan/router.py | 20 +++---- backend/ml_models/Valuation.py | 39 +++++++++++- etl/customers/gla_croydon_demo/asset_list.py | 4 -- etl/customers/goldman/asset_list.py | 63 ++++++++++++++++++++ etl/customers/goldman/epc_f_g_properties.py | 25 ++++++++ recommendations/HeatingRecommender.py | 1 - 8 files changed, 137 insertions(+), 19 deletions(-) create mode 100644 etl/customers/goldman/asset_list.py create mode 100644 etl/customers/goldman/epc_f_g_properties.py diff --git a/.idea/Model.iml b/.idea/Model.iml index b0f9c00d..4413bb06 100644 --- a/.idea/Model.iml +++ b/.idea/Model.iml @@ -7,7 +7,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index 1122b380..6f308057 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,7 +3,7 @@ - + diff --git a/backend/app/plan/router.py b/backend/app/plan/router.py index ebaf482d..06d1aadf 100644 --- a/backend/app/plan/router.py +++ b/backend/app/plan/router.py @@ -282,16 +282,16 @@ async def trigger_plan(body: PlanTriggerRequest): property_id, is_new = create_property( session, body.portfolio_id, epc_searcher.address_clean, epc_searcher.postcode_clean, epc_searcher.uprn ) - # if not is_new: - # continue - # - # create_property_targets( - # session, - # property_id=property_id, - # portfolio_id=body.portfolio_id, - # epc_target=body.goal_value, - # heat_demand_target=None - # ) + if not is_new: + continue + + create_property_targets( + session, + property_id=property_id, + portfolio_id=body.portfolio_id, + epc_target=body.goal_value, + heat_demand_target=None + ) epc_records = { 'original_epc': epc_searcher.newest_epc.copy(), diff --git a/backend/ml_models/Valuation.py b/backend/ml_models/Valuation.py index 39ea5a98..5c781979 100644 --- a/backend/ml_models/Valuation.py +++ b/backend/ml_models/Valuation.py @@ -71,6 +71,14 @@ class PropertyValuation: 90013980: 148_000, # Based on Zoopla 90087154: 184_000, # Based on Zoopla 90046817: 167_000, # Based on Zoopla + # Goldman Sachs Pilot for inrto - search by going to https://www.zoopla.co.uk/property/uprn/{uprn}/ + 100070358888: 153_000, # Based on Zoopla + 10090436544: 282_000, # Based on Zoopla + 100070365751: 177_000, # Based on Zoopla + 10095952767: 168_000, # Based on Zoopla + 100070520130: 177_000, # Based on Zoopla + 100070333957: 185_000, # Based on Zoopla + 100070543258: 211_000, # Based on Zoopla } # We base our valuation uplifts on a number of sources @@ -108,6 +116,29 @@ class PropertyValuation: # {"start": "D", "end": "A", "increase_percentage": 0.017}, ] + # Found here: https://www.rightmove.co.uk/news/articles/property-news/green-premium-epc-ratings/ + # F -> C is + 15% + # E -> C is +7% + # D -> C is +3% + RIGHTMOVE_MAPPING = [ + {"start": "G", "end": "C", "increase_percentage": 0.15}, + {"start": "G", "end": "B", "increase_percentage": 0.15}, + {"start": "G", "end": "A", "increase_percentage": 0.15}, + + {"start": "F", "end": "C", "increase_percentage": 0.15}, + {"start": "F", "end": "B", "increase_percentage": 0.15}, + {"start": "F", "end": "A", "increase_percentage": 0.15}, + + {"start": "E", "end": "C", "increase_percentage": 0.07}, + {"start": "E", "end": "B", "increase_percentage": 0.07}, + {"start": "E", "end": "A", "increase_percentage": 0.07}, + + {"start": "D", "end": "C", "increase_percentage": 0.03}, + {"start": "D", "end": "B", "increase_percentage": 0.03}, + {"start": "D", "end": "A", "increase_percentage": 0.03}, + + ] + EPC_BANDS = ["G", "F", "E", "D", "C", "B", "A"] @classmethod @@ -159,14 +190,18 @@ class PropertyValuation: msm_increase, lloyds_increase = cls.get_increase(epc_band_range) - # We now use the knight frank and nationwide data to get further valuation evidence, if we have it + # We now use the knight frank, nationwide and Rightmove data to get further valuation evidence, if we have it kf_increase = [x for x in cls.KNIGHT_FRANK_MAPPING if x["start"] == current_epc and x["end"] == target_epc] nw_increase = [x for x in cls.NATIONWIDE_MAPPING if x["start"] == current_epc and x["end"] == target_epc] + rm_increase = [x for x in cls.RIGHTMOVE_MAPPING if x["start"] == current_epc and x["end"] == target_epc] kf_increase = kf_increase[0]["increase_percentage"] if kf_increase else None nw_increase = nw_increase[0]["increase_percentage"] if nw_increase else None + rm_increase = rm_increase[0]["increase_percentage"] if rm_increase else None - all_increases = [x for x in [msm_increase, lloyds_increase, kf_increase, nw_increase] if x is not None] + all_increases = [ + x for x in [msm_increase, lloyds_increase, kf_increase, nw_increase, rm_increase] if x is not None + ] max_increase = max(all_increases) min_increase = min(all_increases) diff --git a/etl/customers/gla_croydon_demo/asset_list.py b/etl/customers/gla_croydon_demo/asset_list.py index 1655979b..52e9422c 100644 --- a/etl/customers/gla_croydon_demo/asset_list.py +++ b/etl/customers/gla_croydon_demo/asset_list.py @@ -34,10 +34,6 @@ def app(): low_memory=False ) - z = epc_data[epc_data["MAINHEAT_DESCRIPTION"] == "Boiler and radiators, mains gas"] - z["HOTWATER_DESCRIPTION"].value_counts() - z["MAIN_FUEL"].value_counts() - # Filter on entries where we have a UPRN epc_data = epc_data[~pd.isnull(epc_data["UPRN"])] diff --git a/etl/customers/goldman/asset_list.py b/etl/customers/goldman/asset_list.py new file mode 100644 index 00000000..afe3c64c --- /dev/null +++ b/etl/customers/goldman/asset_list.py @@ -0,0 +1,63 @@ +import pandas as pd +from utils.s3 import read_excel_from_s3 +from utils.s3 import save_csv_to_s3 + +PORTFOLIO_ID = 75 +USER_ID = 8 + + +def app(): + asset_list = [ + { + "address": "19 Emily Gardens", + "postcode": "B16 0ED", + }, + { + "address": "Flat 6 41 Bradford Street", + "postcode": "B5 6HX", + }, + { + "address": "197 FIELD LANE", + "postcode": "B32 4HL", + }, + { + "address": "FLAT 4 108 SUMMER ROAD", + "postcode": "B23 6DY", + }, + { + "address": "1, St. Benedicts Road", + "postcode": "B10 9DP", + }, + { + "address": "29 COOKSEY LANE", + "postcode": "B44 9QL", + }, + { + "address": "40 TRITTIFORD ROAD", + "postcode": "B13 0HG", + } + ] + + asset_list = pd.DataFrame(asset_list) + + # Store the asset list in s3 + filename = f"{USER_ID}/{PORTFOLIO_ID}/pilot.csv" + save_csv_to_s3( + dataframe=asset_list, + bucket_name="retrofit-plan-inputs-dev", + file_name=filename + ) + + # EPC C portoflio + body = { + "portfolio_id": str(PORTFOLIO_ID), + "housing_type": "Private", + "goal": "Increase EPC", + "goal_value": "B", + "trigger_file_path": filename, + "already_installed_file_path": "", + "patches_file_path": "", + "non_invasive_recommendations_file_path": "", + "budget": None, + } + print(body) diff --git a/etl/customers/goldman/epc_f_g_properties.py b/etl/customers/goldman/epc_f_g_properties.py new file mode 100644 index 00000000..28197126 --- /dev/null +++ b/etl/customers/goldman/epc_f_g_properties.py @@ -0,0 +1,25 @@ +import pandas as pd + + +def app(): + """ + Pulling the list of EPC G & F properties in Birmingham for Goldman Sachs + """ + epc_data = pd.read_csv( + "local_data/all-domestic-certificates/domestic-E08000025-Birmingham/certificates.csv", + low_memory=False + ) + + epc_data = epc_data[~pd.isnull(epc_data["UPRN"])] + epc_data["UPRN"] = epc_data["UPRN"].astype(int).astype(str) + + # Get the newest EPC for each UPRN. We use LODGEMENT_DATE as a proxy for this + epc_data["LODGEMENT_DATETIME"] = pd.to_datetime(epc_data["LODGEMENT_DATETIME"], format='mixed') + + epc_data = epc_data.sort_values("LODGEMENT_DATETIME", ascending=False).drop_duplicates("UPRN") + + # Get G & F properties + epc_data = epc_data[epc_data["CURRENT_ENERGY_RATING"].isin(["G", "F"])] + + # Save as an excel + epc_data.to_excel("Birmingham EPC F & G Properties.xlsx", index=False) diff --git a/recommendations/HeatingRecommender.py b/recommendations/HeatingRecommender.py index 537125a1..8988d2a6 100644 --- a/recommendations/HeatingRecommender.py +++ b/recommendations/HeatingRecommender.py @@ -359,7 +359,6 @@ class HeatingRecommender: **heating_simulation_config, **hotwater_simulation_config, **fuel_simulation_config, - "hot_water_energy_eff_ending": "Good" } boiler_costs = self.costs.boiler(