mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
wip
This commit is contained in:
parent
a5ae166971
commit
d68ef88b9d
1 changed files with 85 additions and 22 deletions
|
|
@ -5,6 +5,8 @@ import pandas as pd
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
from docutils.nodes import table
|
||||||
|
|
||||||
|
|
||||||
def years_between(d1, d2):
|
def years_between(d1, d2):
|
||||||
# precise year difference (accounts for months/days)
|
# precise year difference (accounts for months/days)
|
||||||
|
|
@ -16,13 +18,14 @@ def get_element(elements, label):
|
||||||
return elements.get(label)
|
return elements.get(label)
|
||||||
|
|
||||||
|
|
||||||
def append_result(decent_homes_meta, variable, result, install_date=None):
|
def append_result(decent_homes_meta, variable, result, install_date=None, expiry_date=None):
|
||||||
decent_homes_meta.append({
|
decent_homes_meta.append({
|
||||||
"variable": variable,
|
"variable": variable,
|
||||||
"result": result,
|
"result": result,
|
||||||
"hhsrs_rank": None,
|
"hhsrs_rank": None,
|
||||||
"hhsrs_score": None,
|
"hhsrs_score": None,
|
||||||
"install_date": install_date
|
"install_date": install_date,
|
||||||
|
"expiry_date": expiry_date,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -165,11 +168,13 @@ B_COMPONENT_LABELS = {
|
||||||
"Roof Structure 1 in External Area",
|
"Roof Structure 1 in External Area",
|
||||||
"Roof Structure 2 in External Area",
|
"Roof Structure 2 in External Area",
|
||||||
"Roof Structure 3 in External Area",
|
"Roof Structure 3 in External Area",
|
||||||
# If you later decide to include ancillary items, add:
|
"Garage Roof in External Area",
|
||||||
# "Fascia / Soffit / Bargeboard in External Area",
|
"Garage and Store Roofs in External Area",
|
||||||
# "Gutters in External Area", "Downpipes in External Area",
|
"Store Roof in External Area",
|
||||||
# "Internal Downpipes in External Area",
|
"Fascia / Soffit / Bargeboard in External Area",
|
||||||
# and give them a clear condition rule.
|
"Gutters in External Area",
|
||||||
|
"Downpipes in External Area",
|
||||||
|
"Internal Downpipes in External Area"
|
||||||
],
|
],
|
||||||
"roof_finish": [
|
"roof_finish": [
|
||||||
"Roof Covering 1 in External Area",
|
"Roof Covering 1 in External Area",
|
||||||
|
|
@ -198,20 +203,15 @@ B_COMPONENT_LABELS = {
|
||||||
"Store Door in External Area",
|
"Store Door in External Area",
|
||||||
],
|
],
|
||||||
"central_heating_boiler": [
|
"central_heating_boiler": [
|
||||||
# If the dataset exposes a specific boiler element, put it here.
|
# TODO
|
||||||
# For now we only have "Heating Improvement Required in Property" elsewhere (Criterion D),
|
|
||||||
# which isn't reliable for age. If your JSON later includes a boiler line with INSTALL DATE,
|
|
||||||
# add its label here.
|
|
||||||
],
|
],
|
||||||
"heating_other": [
|
"heating_other": [
|
||||||
# e.g., gas fires/storage heaters if present as discrete elements later.
|
# TODO
|
||||||
],
|
],
|
||||||
"electrical_systems": [
|
"electrical_systems": [
|
||||||
# If you have an installation line with dates (e.g. "Electrics Required in Property")
|
# TODO
|
||||||
# add it here; we will rely on INSTALL DATE + REMAINING LIFE.
|
|
||||||
"Electrics Required in Property",
|
"Electrics Required in Property",
|
||||||
],
|
],
|
||||||
|
|
||||||
# Other components
|
# Other components
|
||||||
"kitchen": [
|
"kitchen": [
|
||||||
"Adequacy of Kitchen and Type in Property",
|
"Adequacy of Kitchen and Type in Property",
|
||||||
|
|
@ -287,9 +287,10 @@ COMPONENT_LIFESPANS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Database design
|
# Database design
|
||||||
# creation_date, uprn, variable, result, hhsrs_score (optional, numeric), hhsrs_rank (A-J), install_date (for
|
# creation_date, uprn, variable, result (pass/fail/nodata), hhsrs_score (optional, numeric), hhsrs_rank (A-J),
|
||||||
# components which expire, e.g. kitchen)
|
# install_date (for components which expire, e.g. kitchen), remaining_life (for components which expire, e.g. kitchen),
|
||||||
|
|
||||||
|
# TODO: Add the criterion
|
||||||
decent_homes_meta = []
|
decent_homes_meta = []
|
||||||
# Use to capture criterion A, B, C and D. Should be:
|
# Use to capture criterion A, B, C and D. Should be:
|
||||||
# {"uprn": int, "creation_date": datetime, "criterion_a": bool, "criterion_b": bool, "criterion_c": bool,
|
# {"uprn": int, "creation_date": datetime, "criterion_a": bool, "criterion_b": bool, "criterion_c": bool,
|
||||||
|
|
@ -303,12 +304,15 @@ for fn in filenames:
|
||||||
if property_info["PROP TYPE"] in ["HOU"]:
|
if property_info["PROP TYPE"] in ["HOU"]:
|
||||||
property_type = "house"
|
property_type = "house"
|
||||||
elif property_info["PROP TYPE"] == "FLA":
|
elif property_info["PROP TYPE"] == "FLA":
|
||||||
raise Exception("Implement distrinction between below and above 6 storeys")
|
raise NotImplementedError("Implement distrinction between below and above 6 storeys")
|
||||||
# property_type = "flat"
|
# property_type = "flat"
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("Unknown property type")
|
raise NotImplementedError("Unknown property type")
|
||||||
|
|
||||||
# ---------------- Criterion A ----------------
|
# ---------------- Criterion A ----------------
|
||||||
|
# TODO: Map out the sub-information
|
||||||
|
# Critrion A: pass/fail
|
||||||
|
# If fail, why?
|
||||||
for hhsrs_variable, mapping in HHSRS_MAPPING.items():
|
for hhsrs_variable, mapping in HHSRS_MAPPING.items():
|
||||||
element_code = list(mapping.keys())[0]
|
element_code = list(mapping.keys())[0]
|
||||||
|
|
||||||
|
|
@ -347,19 +351,36 @@ for fn in filenames:
|
||||||
|
|
||||||
component_pass_or_fail = []
|
component_pass_or_fail = []
|
||||||
# TODO: Delete me
|
# TODO: Delete me
|
||||||
component, labels = list(B_COMPONENT_LABELS.items())[1]
|
component, labels = list(B_COMPONENT_LABELS.items())[9]
|
||||||
|
label = labels[0]
|
||||||
|
# TODO: need to handle the case where there is no survey data at all for a component
|
||||||
for component, labels in B_COMPONENT_LABELS.items():
|
for component, labels in B_COMPONENT_LABELS.items():
|
||||||
# TODO: labels may not need to be multiple variables
|
# TODO: labels may not need to be multiple variables
|
||||||
for label in labels:
|
for label in labels:
|
||||||
# Grab the label
|
# Grab the label
|
||||||
label_data = get_element(data["elements"], label)
|
label_data = get_element(data["elements"], label)
|
||||||
|
if label_data["ATTRIBUTE CODE"] in ["UNKNOWN", "NONE", "UNKNOWNG", "UNKNOWNS"]:
|
||||||
|
# This isn't applicable
|
||||||
|
component_pass_or_fail.append(
|
||||||
|
{
|
||||||
|
"component": component,
|
||||||
|
"label": label,
|
||||||
|
"install_date": None,
|
||||||
|
"remaining_life": None,
|
||||||
|
"is_old": False,
|
||||||
|
"has_failed": False,
|
||||||
|
"result": "pass",
|
||||||
|
"appliable": False
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
# 1) We check if the component is old
|
# 1) We check if the component is old
|
||||||
install_date = pd.to_datetime(label_data["INSTALL DATE"])
|
install_date = pd.to_datetime(label_data["INSTALL DATE"])
|
||||||
if pd.isnull(install_date):
|
if pd.isnull(install_date):
|
||||||
raise ValueError("Missing install date - pls check")
|
raise ValueError("Missing install date - pls check")
|
||||||
component_lifetime = COMPONENT_LIFESPANS[component][property_type]
|
component_lifetime = COMPONENT_LIFESPANS[component][property_type]
|
||||||
# This should be populated, and for the pilot it's okay if this errors if missing - we'll handle accordingly
|
# This should be populated, and for the pilot it's okay if this errors if missing - we'll handle accordingly
|
||||||
is_old = years_between(today.to_pydatetime(), install_date.to_pydatetime()) >= component_lifetime
|
is_old = years_between(today.to_pydatetime(), install_date.to_pydatetime()) > component_lifetime
|
||||||
# 2) We check if the component is in poor condition
|
# 2) We check if the component is in poor condition
|
||||||
if pd.isnull(label_data["REMAINING LIFE"]):
|
if pd.isnull(label_data["REMAINING LIFE"]):
|
||||||
raise ValueError("Missing remaining life - pls check")
|
raise ValueError("Missing remaining life - pls check")
|
||||||
|
|
@ -369,15 +390,54 @@ for fn in filenames:
|
||||||
component_pass_or_fail.append(
|
component_pass_or_fail.append(
|
||||||
{
|
{
|
||||||
"component": component,
|
"component": component,
|
||||||
|
"component_type": "key" if component in KEY_COMPONENTS else "other",
|
||||||
|
"component_sub_description": label_data["ATTRIBUTE CODE DESCRIPTION"],
|
||||||
"label": label,
|
"label": label,
|
||||||
"install_date": str(install_date),
|
"install_date": str(install_date),
|
||||||
"remaining_life": label_data["REMAINING LIFE"],
|
"remaining_life": label_data["REMAINING LIFE"],
|
||||||
"is_old": is_old,
|
"is_old": is_old,
|
||||||
"has_failed": has_failed,
|
"has_failed": has_failed,
|
||||||
"result": component_result
|
"result": component_result,
|
||||||
|
"appliable": True
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: We need to check by component
|
||||||
|
# Example of a pass for a component
|
||||||
|
# [
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "A", "result": "pass"},
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "B", "result": "pass"},
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "C", "result": "pass"},
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# Example of a fail for a component
|
||||||
|
# [
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "A", "result": "pass"},
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "B", "result": "fail"},
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "C", "result": "pass"},
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# Example of a no data for a component
|
||||||
|
# [
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "A", "result": "pass"},
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "B", "result": "nodata", "appliable": True},
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "C", "result": "pass"},
|
||||||
|
# ]
|
||||||
|
# OR
|
||||||
|
# Everything is unknown
|
||||||
|
# [
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "A", "result": "pass", "appliable": False},
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "B", "result": "pass", "appliable": False},
|
||||||
|
# {"component": "external_walls", "component_type": "key", "descr": "C", "result": "pass", "appliable": False},
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# Component 1: pass/fail, key: true/False
|
||||||
|
# Component 2: pass/fail, key: true/False
|
||||||
|
# Component 3: pass/fail, key: true/False
|
||||||
|
# Component 4: pass/fail, key: true/False
|
||||||
|
# Component 4: pass/fail, key: true/False
|
||||||
|
# -> Decide on outcome. If failure of 1 key component -> fail criterion B, or 2 other components -> fail criterion B
|
||||||
|
|
||||||
# ---------------- Criterion C ----------------
|
# ---------------- Criterion C ----------------
|
||||||
today = pd.Timestamp.today().normalize()
|
today = pd.Timestamp.today().normalize()
|
||||||
|
|
||||||
|
|
@ -396,7 +456,8 @@ for fn in filenames:
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("Kitchen data missing - pls check")
|
raise NotImplementedError("Kitchen data missing - pls check")
|
||||||
append_result(
|
append_result(
|
||||||
decent_homes_meta, "kitchen_less_than_20_years_old", kitchen_age_result, install_date=str(kit_install)
|
decent_homes_meta, "kitchen_less_than_20_years_old", kitchen_age_result,
|
||||||
|
install_date=str(kit_install), expiry_date=str(kit_next_due)
|
||||||
)
|
)
|
||||||
|
|
||||||
# 2) Kitchen adequate space/layout
|
# 2) Kitchen adequate space/layout
|
||||||
|
|
@ -533,6 +594,8 @@ for fn in filenames:
|
||||||
else:
|
else:
|
||||||
criterion_a_result = "no_data"
|
criterion_a_result = "no_data"
|
||||||
|
|
||||||
|
# ---------------- Criterion B overall ----------------
|
||||||
|
|
||||||
# ---------------- Criterion C overall ----------------
|
# ---------------- Criterion C overall ----------------
|
||||||
criterion_c_vars = [
|
criterion_c_vars = [
|
||||||
"kitchen_less_than_20_years_old",
|
"kitchen_less_than_20_years_old",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue