mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
2044 properties added
This commit is contained in:
parent
a630fe05c4
commit
1b38832e27
1 changed files with 117 additions and 31 deletions
|
|
@ -1938,6 +1938,27 @@ def propsed_wave_3_sample():
|
||||||
)
|
)
|
||||||
].copy()
|
].copy()
|
||||||
|
|
||||||
|
if surveyed.empty:
|
||||||
|
if property["Property Type"].split(":")[0] in ["House", "Bungalow", "Maisonette"]:
|
||||||
|
filter_property_types = ["House", "Bungalow", ]
|
||||||
|
else:
|
||||||
|
filter_property_types = ["Flat"]
|
||||||
|
surveyed = survey_results_with_original_features[
|
||||||
|
(
|
||||||
|
survey_results_with_original_features["Property Type"].str.split(":").str[0].isin(
|
||||||
|
filter_property_types
|
||||||
|
)
|
||||||
|
) &
|
||||||
|
(
|
||||||
|
survey_results_with_original_features["Wall Type"].str.split(":").str[0] ==
|
||||||
|
property["Wall Type"].split(":")[0]
|
||||||
|
) &
|
||||||
|
(
|
||||||
|
survey_results_with_original_features["Roof Type"].str.split(":").str[0] ==
|
||||||
|
property["Roof Type"].split(":")[0]
|
||||||
|
)
|
||||||
|
].copy()
|
||||||
|
|
||||||
if "Electric" in property["Heating"]:
|
if "Electric" in property["Heating"]:
|
||||||
# Take other electric heating systems
|
# Take other electric heating systems
|
||||||
surveyed = surveyed[surveyed["Heating"].str.contains("Electric")]
|
surveyed = surveyed[surveyed["Heating"].str.contains("Electric")]
|
||||||
|
|
@ -1950,6 +1971,9 @@ def propsed_wave_3_sample():
|
||||||
elif property["Heating"] == "Solid fuel room heaters: Open fire in grate":
|
elif property["Heating"] == "Solid fuel room heaters: Open fire in grate":
|
||||||
# Take other properties with room heaters
|
# Take other properties with room heaters
|
||||||
surveyed = surveyed[surveyed["Heating"].str.contains("room heaters")]
|
surveyed = surveyed[surveyed["Heating"].str.contains("room heaters")]
|
||||||
|
elif "Boiler" in property["Heating"]:
|
||||||
|
# Take other properties with boilers
|
||||||
|
surveyed = surveyed[surveyed["Heating"].str.contains("Boiler")]
|
||||||
else:
|
else:
|
||||||
raise Exception("Fix me")
|
raise Exception("Fix me")
|
||||||
|
|
||||||
|
|
@ -1972,17 +1996,29 @@ def propsed_wave_3_sample():
|
||||||
|
|
||||||
# Check if we have a postcode match check if surveyed postcode is the same as the property postcode
|
# Check if we have a postcode match check if surveyed postcode is the same as the property postcode
|
||||||
if any(surveyed["Postcode"] == property["Postcode"]):
|
if any(surveyed["Postcode"] == property["Postcode"]):
|
||||||
surveyed_similar = surveyed[surveyed["Postcode"] == property["Postcode"]]
|
surveyed = surveyed[surveyed["Postcode"] == property["Postcode"]]
|
||||||
|
|
||||||
if any(surveyed["Postal Region"] == property["Postal Region"]):
|
if any(surveyed["Postal Region"] == property["Postal Region"]):
|
||||||
surveyed_similar = surveyed[surveyed["Postal Region"] == property["Postal Region"]]
|
surveyed = surveyed[surveyed["Postal Region"] == property["Postal Region"]]
|
||||||
|
|
||||||
# Take the 5 nearest
|
# Take the 5 nearest
|
||||||
surveyed_similar = surveyed_similar.head(5)
|
surveyed = surveyed.head(5)
|
||||||
|
|
||||||
|
# # We allow a max distance of 10km
|
||||||
|
# surveyed = surveyed[surveyed["distance_meters"] < 10000]
|
||||||
|
# if surveyed.empty:
|
||||||
|
# final_missed_matches.append(
|
||||||
|
# {
|
||||||
|
# "Address ID": a_id,
|
||||||
|
# "Confidence Tier": "4 - no similar property, needs survey to confirm",
|
||||||
|
# "Current EPC Band": "Needs Survey"
|
||||||
|
# }
|
||||||
|
# )
|
||||||
|
# continue
|
||||||
|
|
||||||
# perform a weighted mean of SAP rating - the closer the better
|
# perform a weighted mean of SAP rating - the closer the better
|
||||||
expected_sap = np.average(
|
expected_sap = np.average(
|
||||||
surveyed_similar["Current SAP Rating"], weights=1 / (surveyed_similar["distance_meters"] + 1)
|
surveyed["Current SAP Rating"], weights=1 / (surveyed["distance_meters"] + 1)
|
||||||
)
|
)
|
||||||
expected_epc = sap_to_epc(expected_sap)
|
expected_epc = sap_to_epc(expected_sap)
|
||||||
|
|
||||||
|
|
@ -2153,23 +2189,21 @@ def propsed_wave_3_sample():
|
||||||
# '1 - Archetype surveyed',
|
# '1 - Archetype surveyed',
|
||||||
# '1 - property was surveyed',
|
# '1 - property was surveyed',
|
||||||
# '2 - same archetype',
|
# '2 - same archetype',
|
||||||
# '3 - similar property',
|
# '3 - similar property, weighted on distance'
|
||||||
# '3 - similar property, all areas searched',
|
|
||||||
# '3 - similar property, relaxed conditions'
|
gain_columns = [
|
||||||
|
'1 - Archetype surveyed', '1 - property was surveyed', '2 - same archetype',
|
||||||
|
'3 - similar property, weighted on distance'
|
||||||
|
]
|
||||||
#
|
#
|
||||||
# Loss is the sum of these columns:
|
# Loss is the sum of these columns:
|
||||||
# '4 - no similar property, needs survey to confirm',
|
# '4 - no similar property, needs survey to confirm',
|
||||||
# '5 - EPC C or above', '5 - property was surveyed'
|
# '5 - EPC C or above', '5 - property was surveyed'
|
||||||
geographic_summary["Gain"] = geographic_summary[
|
|
||||||
[
|
|
||||||
'1 - Archetype surveyed', '1 - property was surveyed', '2 - same archetype', '3 - similar property',
|
|
||||||
'3 - similar property, all areas searched', '3 - similar property, relaxed conditions'
|
|
||||||
]
|
|
||||||
].sum(axis=1)
|
|
||||||
|
|
||||||
geographic_summary["Loss"] = geographic_summary[
|
loss_columns = ['4 - no similar property, needs survey to confirm', '5 - EPC C or above',
|
||||||
['5 - EPC C or above', '5 - property was surveyed']
|
'5 - property was surveyed']
|
||||||
].sum(axis=1)
|
geographic_summary["Gain"] = geographic_summary[gain_columns].sum(axis=1)
|
||||||
|
geographic_summary["Loss"] = geographic_summary[loss_columns].sum(axis=1)
|
||||||
|
|
||||||
print(geographic_summary.sum())
|
print(geographic_summary.sum())
|
||||||
|
|
||||||
|
|
@ -2180,30 +2214,82 @@ def propsed_wave_3_sample():
|
||||||
loss = geographic_summary["Loss"].values
|
loss = geographic_summary["Loss"].values
|
||||||
gain = geographic_summary["Gain"].values
|
gain = geographic_summary["Gain"].values
|
||||||
|
|
||||||
# Define the coefficients for the objective function (negative because we maximize Gain)
|
def optimise(gain, loss, max_loss=250):
|
||||||
c = -gain
|
|
||||||
|
|
||||||
# Define constraints
|
# Define the coefficients for the objective function (negative because we maximize Gain)
|
||||||
A = [loss] # Only 1 constraint for now, total Loss
|
c = -gain
|
||||||
b = [250] # Maximum total Loss allowed
|
|
||||||
|
|
||||||
# Bounds for each variable (select or not select each row, 0 <= x <= 1)
|
# Define constraints
|
||||||
bounds = [(0, 1) for _ in gain]
|
A = [loss] # Only 1 constraint for now, total Loss
|
||||||
|
b = [max_loss] # Maximum total Loss allowed
|
||||||
|
|
||||||
# Solve the problem using linprog with HiGHS solver
|
# Bounds for each variable (select or not select each row, 0 <= x <= 1)
|
||||||
result = linprog(c, A_ub=A, b_ub=b, bounds=bounds, method='highs')
|
bounds = [(0, 1) for _ in gain]
|
||||||
if not result.success:
|
|
||||||
raise Exception("Optimization failed")
|
|
||||||
|
|
||||||
selected_rows = result.x.round().astype(int) # Rounded to 0 or 1
|
# Solve the problem using linprog with HiGHS solver
|
||||||
optimal_gain = -result.fun
|
result = linprog(c, A_ub=A, b_ub=b, bounds=bounds, method='highs')
|
||||||
print(optimal_gain)
|
if not result.success:
|
||||||
|
raise Exception("Optimization failed")
|
||||||
|
|
||||||
|
selected_rows = result.x.round().astype(int) # Rounded to 0 or 1
|
||||||
|
optimal_gain = -result.fun
|
||||||
|
|
||||||
|
return selected_rows, optimal_gain
|
||||||
|
|
||||||
|
selected_rows, _ = optimise(gain, loss, 250)
|
||||||
|
|
||||||
# Select the rows that are selected
|
# Select the rows that are selected
|
||||||
geographic_summary["Selected"] = selected_rows == 1
|
geographic_summary["Selected"] = selected_rows == 1
|
||||||
geographic_summary[geographic_summary["Selected"]].sum()
|
geographic_summary[geographic_summary["Selected"]].sum()
|
||||||
bid_size = geographic_summary[geographic_summary["Selected"]][["Gain", "Loss"]].sum().sum()
|
|
||||||
|
region_totals = geographic_summary[
|
||||||
|
geographic_summary["Selected"]
|
||||||
|
][["Gain", "Loss"]].sum()
|
||||||
|
|
||||||
|
# We now see if there are any postcodes that have no loss that can be added
|
||||||
|
unselected_regions = geographic_summary[~geographic_summary["Selected"]]["Postal Region"].values
|
||||||
|
|
||||||
|
postcode_summary = results.pivot_table(
|
||||||
|
index='Postcode',
|
||||||
|
columns='Confidence Tier',
|
||||||
|
aggfunc='size',
|
||||||
|
fill_value=0
|
||||||
|
).reset_index()
|
||||||
|
postcode_summary = postcode_summary.merge(
|
||||||
|
results[["Postcode", "Postal Region"]].drop_duplicates(),
|
||||||
|
how="left", on="Postcode"
|
||||||
|
)
|
||||||
|
|
||||||
|
postcode_summary_unselected_regions = postcode_summary[
|
||||||
|
postcode_summary["Postcode"].str.split(" ").str[0].isin(unselected_regions)
|
||||||
|
].copy()
|
||||||
|
|
||||||
|
postcode_summary_unselected_regions["Gain"] = postcode_summary_unselected_regions[gain_columns].sum(axis=1)
|
||||||
|
postcode_summary_unselected_regions["Loss"] = postcode_summary_unselected_regions[loss_columns].sum(axis=1)
|
||||||
|
|
||||||
|
# Remaining loss allowed
|
||||||
|
remaining_loss_constraint = 250 - region_totals["Loss"]
|
||||||
|
postcode_selected_rows, _ = optimise(
|
||||||
|
gain=postcode_summary_unselected_regions["Gain"].values,
|
||||||
|
loss=postcode_summary_unselected_regions["Loss"].values,
|
||||||
|
max_loss=int(remaining_loss_constraint)
|
||||||
|
)
|
||||||
|
|
||||||
|
postcode_summary_unselected_regions["Selected"] = postcode_selected_rows == 1
|
||||||
|
postcode_summary_unselected_regions[postcode_summary_unselected_regions["Selected"]][["Gain", "Loss"]].sum()
|
||||||
|
|
||||||
|
postcode_optimised_additional_properties = postcode_summary_unselected_regions[
|
||||||
|
postcode_summary_unselected_regions["Selected"]
|
||||||
|
]
|
||||||
|
|
||||||
|
postcode_totals = postcode_optimised_additional_properties[["Gain", "Loss"]].sum()
|
||||||
|
|
||||||
|
bid_size = region_totals.sum() + postcode_totals.sum()
|
||||||
print("Bid Size:", bid_size)
|
print("Bid Size:", bid_size)
|
||||||
|
total_epc_d_or_below = region_totals["Gain"] + postcode_totals["Gain"]
|
||||||
|
print("Total EPC D or below:", total_epc_d_or_below)
|
||||||
|
total_epc_c = region_totals["Loss"] + postcode_totals["Loss"]
|
||||||
|
print("Total EPC C or above:", total_epc_c)
|
||||||
|
|
||||||
# if __name__ == "__main__":
|
# if __name__ == "__main__":
|
||||||
# main()
|
# main()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue