mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
reviewing model performance for vectis - complete
This commit is contained in:
parent
32d702e930
commit
fb3fef5a4a
6 changed files with 142 additions and 82 deletions
|
|
@ -730,77 +730,80 @@ async def trigger_plan(body: PlanTriggerRequest):
|
|||
recommendations[property_id] = recommendations_with_impact
|
||||
|
||||
# For Debugging
|
||||
recommendation_impact_df = []
|
||||
for property_id in recommendations.keys():
|
||||
for recs_by_type in recommendations[property_id]:
|
||||
for rec in recs_by_type:
|
||||
recommendation_impact_df.append(
|
||||
{
|
||||
"property_id": property_id,
|
||||
"uprn": [p.uprn for p in input_properties if p.id == property_id][0],
|
||||
"address": [p.address for p in input_properties if p.id == property_id][0],
|
||||
"recommendation_id": rec["recommendation_id"],
|
||||
"type": rec["type"],
|
||||
"description": rec["description"],
|
||||
"sap_points": rec["sap_points"],
|
||||
"co2_equivalent_savings": rec["co2_equivalent_savings"],
|
||||
"heat_demand": rec["heat_demand"]
|
||||
}
|
||||
)
|
||||
recommendation_impact_df = pd.DataFrame(recommendation_impact_df)
|
||||
|
||||
surveyed_uprns = [
|
||||
10024087855, 121016117, 121016124,
|
||||
10024087902, 121016121, 121016128
|
||||
]
|
||||
recommendation_impact_df = recommendation_impact_df[recommendation_impact_df["uprn"].isin(surveyed_uprns)]
|
||||
# recommendation_impact_df = recommendation_impact_df[recommendation_impact_df["type"].isin(
|
||||
# ["windows_glazing", "internal_wall_insulation"])
|
||||
# recommendation_impact_df = []
|
||||
# for property_id in recommendations.keys():
|
||||
# for recs_by_type in recommendations[property_id]:
|
||||
# for rec in recs_by_type:
|
||||
# recommendation_impact_df.append(
|
||||
# {
|
||||
# "property_id": property_id,
|
||||
# "uprn": [p.uprn for p in input_properties if p.id == property_id][0],
|
||||
# "address": [p.address for p in input_properties if p.id == property_id][0],
|
||||
# "recommendation_id": rec["recommendation_id"],
|
||||
# "type": rec["type"],
|
||||
# "description": rec["description"],
|
||||
# "sap_points": rec["sap_points"],
|
||||
# "co2_equivalent_savings": rec["co2_equivalent_savings"],
|
||||
# "heat_demand": rec["heat_demand"]
|
||||
# }
|
||||
# )
|
||||
# recommendation_impact_df = pd.DataFrame(recommendation_impact_df)
|
||||
#
|
||||
# surveyed_uprns = [
|
||||
# 10024087855, 121016117, 121016124,
|
||||
# 10024087902, 121016121, 121016128
|
||||
# ]
|
||||
|
||||
actual_impacts_df = pd.DataFrame(
|
||||
[
|
||||
# 10024087855
|
||||
{"uprn": 10024087855, "type": "internal_wall_insulation", "actual_sap_points": 5},
|
||||
{"uprn": 10024087855, "type": "draught_proofing", "actual_sap_points": 2},
|
||||
{"uprn": 10024087855, "type": "low_energy_lighting", "actual_sap_points": 0},
|
||||
{"uprn": 10024087855, "type": "windows_glazing", "actual_sap_points": 4},
|
||||
# 121016117
|
||||
{"uprn": 121016117, "type": "internal_wall_insulation", "actual_sap_points": 6},
|
||||
{"uprn": 121016117, "type": "draught_proofing", "actual_sap_points": 1},
|
||||
{"uprn": 121016117, "type": "low_energy_lighting", "actual_sap_points": 1},
|
||||
{"uprn": 121016117, "type": "windows_glazing", "actual_sap_points": 4},
|
||||
# 121016124
|
||||
{"uprn": 121016124, "type": "internal_wall_insulation", "actual_sap_points": 8},
|
||||
{"uprn": 121016124, "type": "low_energy_lighting", "actual_sap_points": 2},
|
||||
{"uprn": 121016124, "type": "windows_glazing", "actual_sap_points": 5},
|
||||
# 10024087902
|
||||
{"uprn": 10024087902, "type": "room_roof_insulation", "actual_sap_points": 16},
|
||||
{"uprn": 10024087902, "type": "internal_wall_insulation", "actual_sap_points": 2},
|
||||
{"uprn": 10024087902, "type": "low_energy_lighting", "actual_sap_points": 0},
|
||||
# 121016121
|
||||
{"uprn": 121016121, "type": "internal_wall_insulation", "actual_sap_points": 5},
|
||||
{"uprn": 121016121, "type": "suspended_floor_insulation", "actual_sap_points": 2},
|
||||
{"uprn": 121016121, "type": "draught_proofing", "actual_sap_points": 1},
|
||||
{"uprn": 121016121, "type": "windows_glazing", "actual_sap_points": 3},
|
||||
# 121016128
|
||||
{"uprn": 121016128, "type": "internal_wall_insulation", "actual_sap_points": 6},
|
||||
{"uprn": 121016128, "type": "suspended_floor_insulation", "actual_sap_points": 1},
|
||||
{"uprn": 121016128, "type": "draught_proofing", "actual_sap_points": 1},
|
||||
{"uprn": 121016128, "type": "low_energy_lighting", "actual_sap_points": 1},
|
||||
{"uprn": 121016128, "type": "windows_glazing", "actual_sap_points": 3},
|
||||
]
|
||||
)
|
||||
|
||||
comparison = recommendation_impact_df.merge(
|
||||
actual_impacts_df, how="inner", on=["uprn", "type"]
|
||||
)
|
||||
|
||||
property_recs = recommendation_impact_df[recommendation_impact_df["uprn"] == 121016128]
|
||||
property = [p for p in input_properties if p.uprn == 121016128][0]
|
||||
print(property.data["current-energy-efficiency"])
|
||||
print(property_recs["sap_points"].sum())
|
||||
property_recs["address"]
|
||||
# recommendation_impact_df = recommendation_impact_df[recommendation_impact_df["uprn"].isin(surveyed_uprns)]
|
||||
# # recommendation_impact_df = recommendation_impact_df[recommendation_impact_df["type"].isin(
|
||||
# # ["windows_glazing", "internal_wall_insulation"])
|
||||
# # ]
|
||||
#
|
||||
# actual_impacts_df = pd.DataFrame(
|
||||
# [
|
||||
# # 10024087855
|
||||
# {"uprn": 10024087855, "type": "internal_wall_insulation", "actual_sap_points": 5},
|
||||
# {"uprn": 10024087855, "type": "draught_proofing", "actual_sap_points": 2},
|
||||
# {"uprn": 10024087855, "type": "low_energy_lighting", "actual_sap_points": 0},
|
||||
# {"uprn": 10024087855, "type": "windows_glazing", "actual_sap_points": 4},
|
||||
# # 121016117
|
||||
# {"uprn": 121016117, "type": "internal_wall_insulation", "actual_sap_points": 6},
|
||||
# {"uprn": 121016117, "type": "draught_proofing", "actual_sap_points": 1},
|
||||
# {"uprn": 121016117, "type": "low_energy_lighting", "actual_sap_points": 1},
|
||||
# {"uprn": 121016117, "type": "windows_glazing", "actual_sap_points": 4},
|
||||
# # 121016124
|
||||
# {"uprn": 121016124, "type": "internal_wall_insulation", "actual_sap_points": 8},
|
||||
# {"uprn": 121016124, "type": "low_energy_lighting", "actual_sap_points": 2},
|
||||
# {"uprn": 121016124, "type": "windows_glazing", "actual_sap_points": 5},
|
||||
# # 10024087902
|
||||
# {"uprn": 10024087902, "type": "room_roof_insulation", "actual_sap_points": 16},
|
||||
# {"uprn": 10024087902, "type": "internal_wall_insulation", "actual_sap_points": 2},
|
||||
# {"uprn": 10024087902, "type": "low_energy_lighting", "actual_sap_points": 0},
|
||||
# # 121016121
|
||||
# {"uprn": 121016121, "type": "internal_wall_insulation", "actual_sap_points": 5},
|
||||
# {"uprn": 121016121, "type": "suspended_floor_insulation", "actual_sap_points": 2},
|
||||
# {"uprn": 121016121, "type": "draught_proofing", "actual_sap_points": 1},
|
||||
# {"uprn": 121016121, "type": "windows_glazing", "actual_sap_points": 3},
|
||||
# # 121016128
|
||||
# {"uprn": 121016128, "type": "internal_wall_insulation", "actual_sap_points": 6},
|
||||
# {"uprn": 121016128, "type": "suspended_floor_insulation", "actual_sap_points": 1},
|
||||
# {"uprn": 121016128, "type": "draught_proofing", "actual_sap_points": 1},
|
||||
# {"uprn": 121016128, "type": "low_energy_lighting", "actual_sap_points": 1},
|
||||
# {"uprn": 121016128, "type": "windows_glazing", "actual_sap_points": 3},
|
||||
# ]
|
||||
# )
|
||||
#
|
||||
# comparison = recommendation_impact_df.merge(
|
||||
# actual_impacts_df, how="inner", on=["uprn", "type"]
|
||||
# )
|
||||
#
|
||||
# print(recommendation_impact_df.groupby(["uprn"])["sap_points"].sum())
|
||||
# property_recs = recommendation_impact_df[recommendation_impact_df["uprn"] == 121016128]
|
||||
# property = [p for p in input_properties if p.uprn == 121016128][0]
|
||||
# print(property.data["current-energy-efficiency"])
|
||||
# print(property_recs["sap_points"].sum())
|
||||
# print(property_recs["type"])
|
||||
# print(float(property.data["current-energy-efficiency"]) + property_recs["sap_points"].sum())
|
||||
# recommendations[property.id][2][0]["simulation_config"]
|
||||
|
||||
# from utils.s3 import read_dataframe_from_s3_parquet
|
||||
# training_data = read_dataframe_from_s3_parquet(
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ SPECIFIC_MEASURES = [
|
|||
# Solar
|
||||
"solar_pv",
|
||||
# Windows Glazing
|
||||
"windows",
|
||||
"double_glazing",
|
||||
"secondary_glazing",
|
||||
# Mechanical ventilation
|
||||
"ventilation",
|
||||
# Other
|
||||
|
|
@ -62,6 +63,7 @@ MEASURE_MAP = {
|
|||
"roof_insulation": ["loft_insulation", "flat_roof_insulation", "room_roof_insulation"],
|
||||
"floor_insulation": ["suspended_floor_insulation", "solid_floor_insulation"],
|
||||
"heating": ["boiler_upgrade", "high_heat_retention_storage_heater", "air_source_heat_pump"],
|
||||
"windows": ["double_glazing", "secondary_glazing"],
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,9 @@ class FloorRecommendations(Definitions):
|
|||
|
||||
simulation_config = {
|
||||
**floor_simulation_config,
|
||||
"floor_thermal_transmittance_ending": new_u_value,
|
||||
# We don't simulate the impact using this U-value, but rather the average because this
|
||||
# variable is way too volatile. Will likely be removed from the model
|
||||
"floor_thermal_transmittance_ending": 0.685593,
|
||||
}
|
||||
|
||||
self.recommendations.append(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import pandas as pd
|
||||
|
||||
from backend.Property import Property
|
||||
from typing import List
|
||||
from recommendations.Costs import Costs
|
||||
|
|
@ -30,6 +32,37 @@ class LightingRecommendations:
|
|||
self.material = material[0]
|
||||
self.recommendation = []
|
||||
|
||||
@classmethod
|
||||
def get_sap_limit(cls, lighting_energy_efficiency: str, lighting_proportion: float):
|
||||
"""
|
||||
Lighting seems to be a more straight forward measure to estimate SAP points for, based on the starting
|
||||
energy efficiency rating.
|
||||
|
||||
We seem to have the following brackes based on % of LEDs in outlets
|
||||
Very poor: 0 - 9%
|
||||
Poor: 10 - 24%
|
||||
Average: 25 - 44%
|
||||
Good: 45 - 69%
|
||||
Very good: 70 - 100%
|
||||
:return:
|
||||
"""
|
||||
|
||||
if lighting_energy_efficiency == "Very Good":
|
||||
return 0
|
||||
|
||||
if lighting_energy_efficiency in ["Good", "Average"]:
|
||||
return cls.SAP_LOWER_LIMIT
|
||||
|
||||
# If lighting_energy_efficiency is missing, we'll use the proportion of low energy lighting
|
||||
if not lighting_energy_efficiency or pd.isnull(lighting_energy_efficiency):
|
||||
if lighting_proportion >= 0.7:
|
||||
return 0
|
||||
if lighting_proportion >= 0.25:
|
||||
return cls.SAP_LOWER_LIMIT
|
||||
return cls.SAP_LIMIT
|
||||
|
||||
return cls.SAP_LIMIT
|
||||
|
||||
@staticmethod
|
||||
def estimate_lighting_impact(number_of_bulbs: int):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -80,6 +80,13 @@ class Recommendations:
|
|||
|
||||
inclusions_full = [MEASURE_MAP[x] if x in MEASURE_MAP else x for x in self.inclusions]
|
||||
exclusions_full = [MEASURE_MAP[x] if x in MEASURE_MAP else x for x in self.exclusions]
|
||||
# We need to unlist any lists, but we should check if they're lists first
|
||||
inclusions_full = [
|
||||
item for sublist in inclusions_full for item in (sublist if isinstance(sublist, list) else [sublist])
|
||||
]
|
||||
exclusions_full = [
|
||||
item for sublist in exclusions_full for item in (sublist if isinstance(sublist, list) else [sublist])
|
||||
]
|
||||
|
||||
# If inclusions and exclusions are empty, it means that nothing was specified, so we allow
|
||||
# all recommendation types
|
||||
|
|
@ -163,9 +170,9 @@ class Recommendations:
|
|||
property_recommendations.append(self.lighting_recommender.recommendation)
|
||||
phase += 1
|
||||
|
||||
if "windows" in measures and "mixed_glazing" not in non_invasive_recommendation_types:
|
||||
if "mixed_glazing" not in non_invasive_recommendation_types:
|
||||
# If we have a mixed glazing recommendation, we prioritise this over the windows recommendation
|
||||
self.windows_recommender.recommend(phase=phase)
|
||||
self.windows_recommender.recommend(phase=phase, measures=measures)
|
||||
if self.windows_recommender.recommendation:
|
||||
property_recommendations.append(self.windows_recommender.recommendation)
|
||||
phase += 1
|
||||
|
|
@ -538,11 +545,11 @@ class Recommendations:
|
|||
|
||||
# For the moment, we cap the number of SAP points that can be achieved by LEDs at 2
|
||||
if rec["type"] == "low_energy_lighting":
|
||||
lighting_sap_limit = LightingRecommendations.get_sap_limit(
|
||||
property_instance.data["lighting-energy-eff"],
|
||||
property_instance.lighting["low_energy_proportion"]
|
||||
)
|
||||
|
||||
if property_instance.data["low-energy-lighting"] < 50:
|
||||
lighting_sap_limit = LightingRecommendations.SAP_LIMIT
|
||||
else:
|
||||
lighting_sap_limit = LightingRecommendations.SAP_LOWER_LIMIT
|
||||
property_phase_impact["sap"] = min(property_phase_impact["sap"], lighting_sap_limit)
|
||||
property_phase_impact["carbon"] = min(
|
||||
property_phase_impact["carbon"], rec["co2_equivalent_savings"]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from typing import List
|
|||
import numpy as np
|
||||
|
||||
from backend.Property import Property
|
||||
from backend.app.plan.schemas import MEASURE_MAP
|
||||
from etl.epc_clean.epc_attributes.WindowAttributes import WindowAttributes
|
||||
from recommendations.Costs import Costs
|
||||
from recommendations.recommendation_utils import override_costs, check_simulation_difference
|
||||
|
|
@ -32,7 +33,7 @@ class WindowsRecommendations:
|
|||
raise ValueError("There should only be one window glazing material")
|
||||
self.glazing_material = self.glazing_material[0]
|
||||
|
||||
def recommend(self, phase=0):
|
||||
def recommend(self, measures=None, phase=0):
|
||||
"""
|
||||
This method will recommend the best possible glazing options for a property.
|
||||
|
||||
|
|
@ -41,14 +42,26 @@ class WindowsRecommendations:
|
|||
:return:
|
||||
"""
|
||||
|
||||
measures = MEASURE_MAP["windows"] if measures is None else measures
|
||||
|
||||
# If we have no windows recs, leave
|
||||
if not any(x in measures for x in MEASURE_MAP["windows"]):
|
||||
return
|
||||
|
||||
# If the property is in a conservation area or is a listed building, it becomes more difficult to install
|
||||
# double glazing. Therefore, we don't recommend it. It is still possible but is not practical as it
|
||||
# requires planning permission and might require a more expensive window type, such as timber.
|
||||
|
||||
number_of_windows = self.property.number_of_windows
|
||||
is_secondary_glazing = self.property.restricted_measures or (
|
||||
self.property.windows["glazing_type"] == "secondary"
|
||||
)
|
||||
|
||||
if "double_glazing" in measures and "secondary_glazing" not in measures:
|
||||
is_secondary_glazing = False
|
||||
elif "secondary_glazing" in measures and "double_glazing" not in measures:
|
||||
is_secondary_glazing = True
|
||||
else:
|
||||
is_secondary_glazing = self.property.restricted_measures or (
|
||||
self.property.windows["glazing_type"] == "secondary"
|
||||
)
|
||||
windows_area = self.property.windows_area
|
||||
|
||||
if not number_of_windows:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue