mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
debugging a recommendation for hhrsh where the property currently has underfloor heating
This commit is contained in:
parent
b81e2a4eba
commit
53e0a651c9
8 changed files with 137 additions and 3 deletions
2
.idea/Model.iml
generated
2
.idea/Model.iml
generated
|
|
@ -7,7 +7,7 @@
|
||||||
<sourceFolder url="file://$MODULE_DIR$/open_uprn" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/open_uprn" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/recommendations" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/recommendations" isTestSource="false" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="AssetList" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Fastapi-backend" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
|
|
@ -3,7 +3,7 @@
|
||||||
<component name="Black">
|
<component name="Black">
|
||||||
<option name="sdkName" value="Python 3.10 (backend)" />
|
<option name="sdkName" value="Python 3.10 (backend)" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="AssetList" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Fastapi-backend" project-jdk-type="Python SDK" />
|
||||||
<component name="PyCharmProfessionalAdvertiser">
|
<component name="PyCharmProfessionalAdvertiser">
|
||||||
<option name="shown" value="true" />
|
<option name="shown" value="true" />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
||||||
|
|
@ -96,3 +96,7 @@ class PlanTriggerRequest(BaseModel):
|
||||||
# When performing a remote assessment, if this has been set, it will allow the engine to
|
# When performing a remote assessment, if this has been set, it will allow the engine to
|
||||||
# pull data from the find my epc website, to utilise as part of a remote assessment
|
# pull data from the find my epc website, to utilise as part of a remote assessment
|
||||||
event_type: Optional[Literal["remote_assessment"]] = None
|
event_type: Optional[Literal["remote_assessment"]] = None
|
||||||
|
|
||||||
|
# If true, before optimising the engine will select a slightly larger package, to account for the SAP 10 causing
|
||||||
|
# scores to drop by a few points
|
||||||
|
simulate_sap_10: Optional[bool] = False
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ import backend.app.assumptions as assumptions
|
||||||
|
|
||||||
from backend.ml_models.api import ModelApi
|
from backend.ml_models.api import ModelApi
|
||||||
from backend.Property import Property
|
from backend.Property import Property
|
||||||
from backend.Funding import Funding
|
|
||||||
from backend.apis.GoogleSolarApi import GoogleSolarApi
|
from backend.apis.GoogleSolarApi import GoogleSolarApi
|
||||||
|
|
||||||
from recommendations.optimiser.CostOptimiser import CostOptimiser
|
from recommendations.optimiser.CostOptimiser import CostOptimiser
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,10 @@ class HeatingRecommender:
|
||||||
},
|
},
|
||||||
# These are the heating types we need to produce a dual heating recommendation
|
# These are the heating types we need to produce a dual heating recommendation
|
||||||
"dual": None
|
"dual": None
|
||||||
|
},
|
||||||
|
'Electric underfloor heating, electric storage heaters': {
|
||||||
|
# For this, we would recommend a heat pump
|
||||||
|
"dual": None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,6 +113,10 @@ class HeatingRecommender:
|
||||||
|
|
||||||
hhr_suitable = no_mains or self.has_electric_heating_description or self.has_room_heaters
|
hhr_suitable = no_mains or self.has_electric_heating_description or self.has_room_heaters
|
||||||
|
|
||||||
|
hhr_suitable = hhr_suitable and (
|
||||||
|
"underfloor heating" not in self.property.main_heating["clean_description"]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
hhr_suitable and (not ashp_only_heating_recommendation) and not self.has_ashp and
|
hhr_suitable and (not ashp_only_heating_recommendation) and not self.has_ashp and
|
||||||
("high_heat_retention_storage_heater" in measures)
|
("high_heat_retention_storage_heater" in measures)
|
||||||
|
|
|
||||||
47
sfr/principal_pitch/0_prepare_sample.py
Normal file
47
sfr/principal_pitch/0_prepare_sample.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
"""
|
||||||
|
This is a script for preparing a sample for testing the end to end process, so that when Spring send us
|
||||||
|
data, we know it will work.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
birmingham_epcs = pd.read_csv(
|
||||||
|
"/Users/khalimconn-kowlessar/Documents/hestia/sfr/Spring JV/domestic-E08000025-Birmingham/certificates.csv"
|
||||||
|
)
|
||||||
|
|
||||||
|
# We get the newest EPC, by UPRN and LODGEMENT_DATE
|
||||||
|
birmingham_epcs['LODGEMENT_DATE'] = pd.to_datetime(birmingham_epcs['LODGEMENT_DATE'])
|
||||||
|
|
||||||
|
birmingham_epcs = birmingham_epcs.sort_values(
|
||||||
|
by=['UPRN', 'LODGEMENT_DATE'],
|
||||||
|
ascending=[True, False]
|
||||||
|
).drop_duplicates(subset='UPRN')
|
||||||
|
|
||||||
|
# Take a sample of properties, EPC F or G, EPC lodged in 2025. We focus on houses/bingalows
|
||||||
|
sample = birmingham_epcs[
|
||||||
|
(birmingham_epcs['CURRENT_ENERGY_RATING'].isin(['F', 'G'])) &
|
||||||
|
(birmingham_epcs['LODGEMENT_DATE'] >= '2025-01-01') &
|
||||||
|
(birmingham_epcs['PROPERTY_TYPE'].isin(['House', 'Bungalow']))
|
||||||
|
]
|
||||||
|
|
||||||
|
# Prepare the sample, with just the columns we would expect to receive from Spring
|
||||||
|
# 1) UPRN
|
||||||
|
# 2) Address
|
||||||
|
# 3) Postcode
|
||||||
|
# 4) Property type
|
||||||
|
# 5) Built form
|
||||||
|
# 6) Number of bedrooms (we'll simulate this)
|
||||||
|
# 7) Number of bathrooms (we'll simulate this)
|
||||||
|
# 8) Valuation (We'll simulate this, around 200,000)
|
||||||
|
|
||||||
|
sample = sample[['UPRN', 'ADDRESS', 'POSTCODE', 'PROPERTY_TYPE', 'BUILT_FORM']].copy()
|
||||||
|
sample['BEDROOMS'] = 3 # Simulating number of bedrooms
|
||||||
|
sample['BATHROOMS'] = 1 # Simulating number of bathrooms
|
||||||
|
sample['VALUATION'] = 200000 # Simulating valuation
|
||||||
|
sample.columns = [x.lower() for x in sample.columns]
|
||||||
|
|
||||||
|
# Store this as a excel
|
||||||
|
sample.to_excel(
|
||||||
|
"/Users/khalimconn-kowlessar/Documents/hestia/sfr/Spring JV/birmingham_sample.xlsx",
|
||||||
|
index=False
|
||||||
|
)
|
||||||
76
sfr/principal_pitch/1_prepare_data.py
Normal file
76
sfr/principal_pitch/1_prepare_data.py
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
"""
|
||||||
|
This script prepares the data for the principal pitch modelling
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import pandas as pd
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from utils.s3 import save_csv_to_s3
|
||||||
|
from etl.find_my_epc.AssetListEpcData import AssetListEpcData
|
||||||
|
|
||||||
|
load_dotenv(dotenv_path="backend/.env")
|
||||||
|
EPC_AUTH_TOKEN = os.getenv("EPC_AUTH_TOKEN")
|
||||||
|
PORTFOLIO_ID = 206
|
||||||
|
USER_ID = 8
|
||||||
|
EPC_TARGET = "C"
|
||||||
|
|
||||||
|
# Read the input file
|
||||||
|
|
||||||
|
properties = pd.read_excel(
|
||||||
|
"/Users/khalimconn-kowlessar/Documents/hestia/sfr/Spring JV/birmingham_sample.xlsx"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Pull the non-invasive recommendations
|
||||||
|
asset_list_epc_client = AssetListEpcData(
|
||||||
|
asset_list=properties,
|
||||||
|
epc_auth_token=EPC_AUTH_TOKEN
|
||||||
|
)
|
||||||
|
asset_list_epc_client.get_data()
|
||||||
|
asset_list_epc_client.get_non_invasive_recommendations()
|
||||||
|
asset_list_epc_client.get_patch()
|
||||||
|
# TODO; Find some new, on-market opportunities that aren't on the EPC API, so we definitely have a patch
|
||||||
|
|
||||||
|
# Store the asset list in s3
|
||||||
|
filename = f"{USER_ID}/{PORTFOLIO_ID}/asset_list.csv"
|
||||||
|
save_csv_to_s3(
|
||||||
|
dataframe=properties,
|
||||||
|
bucket_name="retrofit-plan-inputs-dev",
|
||||||
|
file_name=filename
|
||||||
|
)
|
||||||
|
|
||||||
|
# Store non-invasive recommendations in S3
|
||||||
|
non_invasive_recommendations_filename = f"{USER_ID}/{PORTFOLIO_ID}/non_invasive_recommendations.csv"
|
||||||
|
save_csv_to_s3(
|
||||||
|
dataframe=pd.DataFrame(asset_list_epc_client.non_invasive_recommendations),
|
||||||
|
bucket_name="retrofit-plan-inputs-dev",
|
||||||
|
file_name=non_invasive_recommendations_filename
|
||||||
|
)
|
||||||
|
|
||||||
|
# Store patches in S3
|
||||||
|
patches_filename = ""
|
||||||
|
if asset_list_epc_client.patches:
|
||||||
|
patches_filename = f"{USER_ID}/{PORTFOLIO_ID}/patches.csv"
|
||||||
|
save_csv_to_s3(
|
||||||
|
dataframe=pd.DataFrame(asset_list_epc_client.patches),
|
||||||
|
bucket_name="retrofit-plan-inputs-dev",
|
||||||
|
file_name=patches_filename
|
||||||
|
)
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"portfolio_id": str(PORTFOLIO_ID),
|
||||||
|
"housing_type": "Private",
|
||||||
|
"goal": "Increasing EPC",
|
||||||
|
"goal_value": "C",
|
||||||
|
"trigger_file_path": filename,
|
||||||
|
"already_installed_file_path": "",
|
||||||
|
"patches_file_path": patches_filename,
|
||||||
|
"non_invasive_recommendations_file_path": non_invasive_recommendations_filename,
|
||||||
|
"valuation_file_path": "",
|
||||||
|
"scenario_name": "EPC C",
|
||||||
|
"multi_plan": True,
|
||||||
|
"budget": None,
|
||||||
|
"ashp_cop": 3.5,
|
||||||
|
# This is new - when optimising, we drop scores by a few points to account for SAP 10
|
||||||
|
"simulate_sap_10": True,
|
||||||
|
"exclusions": ["external_wall_insulation"]
|
||||||
|
}
|
||||||
|
print(body)
|
||||||
0
sfr/principal_pitch/2_export_data.py
Normal file
0
sfr/principal_pitch/2_export_data.py
Normal file
Loading…
Add table
Reference in a new issue