diff --git a/etl/eligibility/ha_15_32/ha_analysis_batch_3.py b/etl/eligibility/ha_15_32/ha_analysis_batch_3.py index 4f33bf34..191ca74c 100644 --- a/etl/eligibility/ha_15_32/ha_analysis_batch_3.py +++ b/etl/eligibility/ha_15_32/ha_analysis_batch_3.py @@ -1692,500 +1692,500 @@ def get_col_widths(dataframe): return widths -def analyse_ha_data(outputs, loader): - """ - The approach we take within this function is the following: - For properties that have been identified by warmfront as eligible properties, characterise them by scheme. The - characterisation can be broken down as the following: - 1) The property has been identified by Warmfront and is eligible for ECO4/GBIS work, under the strictest criteria - 2) The property has been identified by Warmfront, however it has a full cavity, and therefore would be subject to - a CIGA check - 3) The property has been identified by Warmfront, but the EPC shows that the property has more than 100mm loft - insulation - 4) The property has been identified by Warmfront, but doesn't look like a property that would likely qualify under - any cirsumstances, given the available data - - Then, for any property that has NOT been identifid by Warmfront, we identify properties that look like they would - qualify under the strictest criteria, and mark these as potential additional opportunities. - - :return: - """ - - eco4_rate = 1710 - gbis_rate = 600 - old_eco4_rate = 1456 - old_gbis_rate = 432 - - epc_c_threshold = 80 - scheme_map = { - "ECO4": "ECO4", - "AFFORDABLE WARMTH": "ECO4", - "ECO4 A/W": "ECO4", - "ECO4 GBIS (ECO+)": "GBIS" - } - - ha_analysis_results = [] - total_revenue_results = [] - for ha_name, datasets in outputs.items(): - inputs = [x for k, x in loader.data.items() if k == ha_name][0] - - results_df = datasets["results_df"].copy() - - analysis_data = inputs["asset_list"][['asset_list_row_id', "ECO Eligibility"]].rename( - columns={"row_meaning": "asset_identification_status"} - ).merge( - results_df, - how="left", - right_on="row_id", - left_on="asset_list_row_id" - ) - - analysis_data["is_remaining"] = True - - n_sold_eco4 = 0 - n_sold_gbis = 0 - if not inputs["survey_list"].empty: - # Merge on the survey list and signal everything that is remaining or not (i.e. anything that hasn't had - # a survey) - survey_list = inputs["survey_list"].copy() - - # TODO: TEMP - scheme_column = survey_list.columns[0] - # We clean up the survey list installation or cancelled - survey_list["installed_or_cancelled_clean"] = survey_list["INSTALLED OR CANCELLED"].str.lower() - # Remove all punctuation - survey_list["installed_or_cancelled_clean"] = survey_list["installed_or_cancelled_clean"].str.replace( - r'[^\w\s]', '', regex=True - ) - # Remove double spaces - survey_list["installed_or_cancelled_clean"] = survey_list["installed_or_cancelled_clean"].str.replace( - r'\s+', ' ', regex=True - ) - # Remove trailing spaces - survey_list["installed_or_cancelled_clean"] = survey_list["installed_or_cancelled_clean"].str.strip() - - # Remap the values in the scheme column - survey_list[scheme_column] = survey_list[scheme_column].replace(scheme_map) - - survey_list["installation_status"] = None - survey_list["installation_status"] = np.where( - survey_list["installed_or_cancelled_clean"].isin(["installed", "installed see notes"]), - "installed", - survey_list["installation_status"] - ) - survey_list["installation_status"] = np.where( - survey_list["installed_or_cancelled_clean"].isin(["cancelled"]), - "cancelled", - survey_list["installation_status"] - ) - # Find partial installations - survey_list["installation_status"] = np.where( - survey_list["installed_or_cancelled_clean"].str.contains("still to be installed"), - "partially installed", - survey_list["installation_status"] - ) - # Find partial cancellations - # TODO: We might have more indications of partial cancellations - survey_list["installation_status"] = np.where( - survey_list["installed_or_cancelled_clean"].isin(["loft cancelled"]), - "partially cancelled", - survey_list["installation_status"] - ) - - # Finally, for other cases, we set the status to "in progress" - survey_list["installation_status"] = survey_list["installation_status"].fillna("in progress") - - # We concatenate the scheme name with the installation status - survey_list["installation_status"] = ( - survey_list[scheme_column] + " - " + survey_list["installation_status"] - ) - - # TODO: END TEMP - - survey_list_to_merge = survey_list[["asset_list_row_id", scheme_column]].copy() - survey_list_to_merge["is_remaining"] = False - analysis_data = analysis_data.drop(columns="is_remaining").merge( - survey_list_to_merge, - how="left", on="asset_list_row_id" - ) - analysis_data["is_remaining"] = analysis_data["is_remaining"].fillna(True) - - n_sold_eco4 = survey_list_to_merge[survey_list_to_merge[scheme_column] == "ECO4"].shape[0] - n_sold_gbis = survey_list_to_merge[survey_list_to_merge[scheme_column] == "GBIS"].shape[0] - - # Take just remaining - analysis_data = analysis_data[analysis_data["is_remaining"]] - - # Also, if the HA has started selling, we remove any that are still subject to ciga - n_eco4_missed_subject_to_ciga = 0 - if not inputs["survey_list"].empty: - n_eco4_missed_subject_to_ciga = (analysis_data["ECO Eligibility"] == "eco4 (subject to ciga)").sum() - analysis_data = analysis_data[analysis_data["ECO Eligibility"] != "eco4 (subject to ciga)"] - - ################################################################################################ - # We take the properties that strictly qualified under eco - ################################################################################################ - - eco4_identified = analysis_data[analysis_data["ECO Eligibility"] == "eco4"].copy() - eco4_identified["identification_type"] = None - eco4_identified["identification_type"] = np.where( - (eco4_identified["eco4_eligible"] == True) & (eco4_identified["eco4_strict"] == True), - "strict", - eco4_identified["identification_type"] - ) - - # For expansive, the property can be no higher than an EPC C - eco4_identified["identification_type"] = np.where( - (eco4_identified["eco4_eligible"] == True) & (eco4_identified["eco4_strict"] == False) & ( - eco4_identified["sap"] <= epc_c_threshold - ), - "expansive", - eco4_identified["identification_type"] - ) - ################################################################################################ - # We take the properties dependent on CIGA - ################################################################################################ - - ciga_dependent_identified = analysis_data[ - analysis_data["ECO Eligibility"].isin( - [ - "eco4 (subject to ciga)", - "eco4 - passed ciga" - ] - ) - ].copy() - - # These are properties that show filled cavity - ciga_dependent_identified["identification_type"] = None - ciga_dependent_identified["identification_type"] = np.where( - ciga_dependent_identified["eco4_message"].isin( - [ - "Perfect suitability", - "Meets cavity and sap", - "Fails cavity, meets loft, fails SAP", - "Meets fabric, fails SAP check", - "Meets cavity, loft borderline, meets sap", - ] - ) & (ciga_dependent_identified["sap"] <= epc_c_threshold), - "strict", - ciga_dependent_identified["identification_type"] - ) - - ciga_dependent_identified["identification_type"] = np.where( - ((ciga_dependent_identified["eco4_message"].isin(["Meets just cavity"])) | ( - ciga_dependent_identified["walls"].isin(["Cavity wall, filled cavity"]) - )) & ( - (ciga_dependent_identified["sap"] <= epc_c_threshold) & - pd.isnull(ciga_dependent_identified["identification_type"]) - ), - "expansive", - ciga_dependent_identified["identification_type"] - ) - - ################################################################################################ - # We properties that qualified for gbis - ################################################################################################ - gbis_identified = analysis_data[analysis_data["ECO Eligibility"] == "gbis"].copy() - gbis_identified["identification_type"] = None - gbis_identified["identification_type"] = np.where( - (gbis_identified["gbis_eligible"] == True) & (gbis_identified["sap"] < 69), - "strict", - gbis_identified["identification_type"] - ) - - gbis_identified["identification_type"] = np.where( - (gbis_identified["gbis_eligible"] == True) & (gbis_identified["sap"] <= epc_c_threshold) & ( - pd.isnull(gbis_identified["identification_type"]) - ), - "expansive", - gbis_identified["identification_type"] - ) - - # Finally, we look at the properties that have not been identified by Warmfront - not_identified = analysis_data[ - analysis_data["ECO Eligibility"].isin( - [ - "not eligible" - ] - ) - ].copy() - - surplus_eco4 = not_identified[ - (not_identified["eco4_eligible"] == True) & (not_identified["eco4_message"].isin( - ["Perfect suitability", "Meets cavity, loft borderline, meets sap", "Near perfect suitability"] - )) - ] - - surplus_gbis = not_identified[ - (not_identified["gbis_eligible"] == True) & ( - ~not_identified["asset_list_row_id"].isin(surplus_eco4["asset_list_row_id"].values) - ) & (not_identified["sap"] < 69) & ( - (not_identified["cavity_type"].isin(["empty", "partial insulation"])) | ( - not_identified["walls"].str.contains("partial", case=False, na=False) - ) - ) - ] - surplus_gbis = surplus_gbis[surplus_gbis["is_estimated"] == False] - - # Output variables - the data was sent to us in December, but the remaining figures are - # what was in November - november_remaining = loader.december_figures[loader.december_figures["HA Name"] == ha_name] - - # ECO4 - n_properties_remaining_in_asset_list = inputs["asset_list"].shape[0] - november_eco4_remaining = max(november_remaining["ECO4 remaining"].values[0], 0) - november_eco4_sold = november_remaining["No. of Tech surveys complete - Eco 4"].values[0] - eco4_sales_since_november = n_sold_eco4 - november_eco4_sold - - n_warmfront_identified_eco4 = eco4_identified.shape[0] + ciga_dependent_identified.shape[0] - eco4_of_which_identified_strict = ( - eco4_identified[eco4_identified["identification_type"] == "strict"].shape[0] + - ciga_dependent_identified[ciga_dependent_identified["identification_type"] == "strict"].shape[0] - ) - eco4_of_which_identified_expansive = ( - eco4_identified[eco4_identified["identification_type"] == "expansive"].shape[0] + - ciga_dependent_identified[ciga_dependent_identified["identification_type"] == "expansive"].shape[0] - ) - # GBIS - n_warmfront_identified_gbis = gbis_identified.shape[0] - november_gbis_remaining = max(november_remaining["GBIS remaining"].values[0], 0) - november_gbis_sold = november_remaining["No. of Tech surveys complete - GBIS"].values[0] - gbis_sales_since_november = n_sold_gbis - november_gbis_sold - gbis_of_which_identified_strict = gbis_identified[gbis_identified["identification_type"] == "strict"].shape[0] - gbis_of_which_identified_expansive = \ - gbis_identified[gbis_identified["identification_type"] == "expansive"].shape[0] - - to_append = { - ("", "HA Name"): ha_name, - ("", "# properties in asset list"): n_properties_remaining_in_asset_list, - ############ - # ECO4 - ############ - ("ECO4", "# remaining November file"): november_eco4_remaining, - ("ECO4", "# sold in November file"): november_eco4_sold, - ("ECO4", "# sold (survey list)"): n_sold_eco4, - ("ECO4", "# that missed CIGA check"): n_eco4_missed_subject_to_ciga, - ("ECO4", "# Remaining properties (asset list)"): n_warmfront_identified_eco4, - ("ECO4", "Of which identified by model - strict"): eco4_of_which_identified_strict, - ("ECO4", "Of which identified by model - expansive"): eco4_of_which_identified_expansive, - ("ECO4", "Of which identified by model - total"): ( - eco4_of_which_identified_strict + eco4_of_which_identified_expansive - ), - ("ECO4", "Additional properties"): surplus_eco4.shape[0], - ############ - # GBIS - ############ - ("GBIS", "# remaining November file"): november_gbis_remaining, - ("GBIS", "# sold in November file"): november_gbis_sold, - ("GBIS", "# sold (survey list)"): n_sold_gbis, - ("GBIS", "# Remaining properties (asset list)"): n_warmfront_identified_gbis, - ("GBIS", "Of which identified by model - strict"): gbis_of_which_identified_strict, - ("GBIS", "Of which identified by model - expansive"): gbis_of_which_identified_expansive, - ("GBIS", "Of which identified by model - total"): ( - gbis_of_which_identified_strict + gbis_of_which_identified_expansive - ), - ("GBIS", "Additional properties"): surplus_gbis.shape[0] - } - - ha_analysis_results.append(to_append) - - # Calculate the revenue results - to_append_revenue = { - ("", "HA Name"): ha_name, - # Eco4 revenue - ("ECO4", "£ remaining November file"): november_eco4_remaining * eco4_rate, - ("ECO4", "£ sold November file"): november_eco4_sold * old_eco4_rate, - ("ECO4", "£ sold since November"): eco4_sales_since_november * eco4_rate, - ("ECO4", "£ stuck at ciga check"): n_eco4_missed_subject_to_ciga * eco4_rate, - ("ECO4", "£ remaining (asset list)"): n_warmfront_identified_eco4 * eco4_rate, - ("ECO4", "Of which identified by model - strict"): eco4_of_which_identified_strict * eco4_rate, - ("ECO4", "Of which identified by model - expansive"): eco4_of_which_identified_expansive * eco4_rate, - ("ECO4", "Of which identified by model - total"): eco4_rate * ( - eco4_of_which_identified_strict + eco4_of_which_identified_expansive - ), - ("ECO4", "Additional properties"): eco4_rate * surplus_eco4.shape[0], - } - total_revenue_results.append(to_append_revenue) - - ha_analysis_results = pd.DataFrame(ha_analysis_results) - ha_analysis_results.columns = pd.MultiIndex.from_tuples(ha_analysis_results.columns) - - facts_and_figures = loader.facts_and_figures.copy() - facts_and_figures["ha_number"] = facts_and_figures["HA Name"].str.extract(r'(\d+)').astype(int) - facts_and_figures = facts_and_figures.sort_values("ha_number") - facts_and_figures = facts_and_figures.drop(columns=["ha_number"]) - - # Rename some of the cols - facts_and_figures = facts_and_figures.rename( - columns={ - # ECO4 cols - "ECO4": "ECO4 - November", - "GBIS": "GBIS - November", - "eco4 (subject to ciga)": "ECO4 - subject to ciga", - "eco4": "ECO4 - doesn't need CIGA", - "eco4 - passed ciga": "ECO4 - passed CIGA", - "failed ciga": "ECO4 - failed CIGA", - "ECO4 - partially cancelled": "ECO4 - Install downgrade to GBIS", - "ECO4 - in progress": "ECO4 - Install in progress", - "ECO4 - cancelled": "ECO4 - Install cancelled", - # GBIS cols - "gbis": "GBIS total (asset list)" - } - ) - # We calculate the eco4 total from the asset list - # 1) If ciga checks have been completed (i.e. ECO4 - passed ciga > 0) this sum is - # ECO4 - doesn't need CIGA + ECO4 - passed CIGA - # 2) if ciga checks haven't been completed (i.e. ECO4 - passed ciga is missing), this sum is - # ECO4 - doesn't need CIGA + ECO4 - subject to ciga - facts_and_figures["ECO4 total (asset list - pre ciga)"] = ( - facts_and_figures["ECO4 - doesn't need CIGA"] + - facts_and_figures["ECO4 - subject to ciga"] + - facts_and_figures["ECO4 - passed CIGA"] - ) - - facts_and_figures["ECO4 total (asset list - post ciga)"] = None - facts_and_figures["ECO4 total (asset list - post ciga)"] = np.where( - facts_and_figures["ECO4 - passed CIGA"] > 0, - facts_and_figures["ECO4 - doesn't need CIGA"] + facts_and_figures["ECO4 - passed CIGA"], - facts_and_figures["ECO4 total (asset list - post ciga)"] - ) - - # Re-arrange the columns - facts_and_figures = facts_and_figures[ - [ - 'HA Name', - 'ECO4 - November', - 'GBIS - November', - 'ECO4 total (asset list - pre ciga)', - 'ECO4 total (asset list - post ciga)', - 'GBIS total (asset list)', - 'ECO4 - subject to ciga', - "ECO4 - doesn't need CIGA", - 'ECO4 - passed CIGA', - 'ECO4 - failed CIGA', - 'ECO4 - installed', - 'ECO4 - Install in progress', - 'ECO4 - Install cancelled', - 'ECO4 - partially installed', - 'ECO4 - Install downgrade to GBIS', - ] - ] - # Addd a note to flag any rows where ECO4 ( - # subject to ciga is greater than 0) and (ECO4 - passed ciga is greater than 0 - # ) - facts_and_figures["Missed CIGA checks opportunity"] = None - facts_and_figures["Missed CIGA checks opportunity"] = np.where( - (facts_and_figures["ECO4 - subject to ciga"] > 0) & (facts_and_figures["ECO4 - passed CIGA"] > 0), - "potential opportunity of " + facts_and_figures["ECO4 - subject to ciga"].astype( - str) + " ECO4 properties needing a CIGA check", - facts_and_figures["Missed CIGA checks opportunity"] - ) - - facts_and_figures.to_csv("Facts and figures sample.csv") - - # Re arrage the columns - - # Also sort ha_analysis_results by ha number - ha_analysis_results["ha_number"] = ha_analysis_results[("", "HA Name")].str.extract(r'(\d+)').astype(int) - ha_analysis_results = ha_analysis_results.sort_values("ha_number") - ha_analysis_results = ha_analysis_results.drop(columns=["ha_number"]) - - # We save 2 sheets - # Automate creation of the excel - # Create a Pandas Excel writer using XlsxWriter as the engine - with pd.ExcelWriter('HA Analysis Results.xlsx', engine='xlsxwriter') as writer: - # Write each dataframe to a different worksheet without the index - for df, sheet in [(facts_and_figures, 'HA Facts and Figures'), - (ha_analysis_results, 'Asset Identification')]: - - df.to_excel(writer, sheet_name=sheet) - - # Auto-adjust columns' width - for i, width in enumerate(get_col_widths(df)): - writer.sheets[sheet].set_column(i, i, width) - - # Inspection: - Looking into the proportion of homes with "cavity, as built, insulated (assumed)" as their - # description, and what proportion of time they get identified via non-invasive surveys - - # true_eco4_assets = [] - # ciga_dependent_assets = [] - # not_eligible = [] - # as_built_insulated = [] - # date_cols = { - # "HA39": "date_built", - # "HA14": "Built In Year", - # "HA6": "Construction Year", - # "HA1": "Build Date", - # "HA107": "YEAR BUILT" - # } - # for ha_name, data_objects in outputs.items(): - # inputs = [x for k, x in loader.data.items() if k == ha_name][0] - # - # date_col = date_cols[ha_name] - # results_df = data_objects["results_df"].copy() - # df = inputs["asset_list"][['asset_list_row_id', "ECO Eligibility", date_col]].rename( - # columns={"row_meaning": "asset_identification_status", date_col: "date_built"} - # ).merge( - # results_df, - # how="left", - # right_on="row_id", - # left_on="asset_list_row_id" - # ) - # - # # take the true ECO4 - # true_eco4 = df[df["ECO Eligibility"] == "eco4"].copy() - # ciga_dependent = df[ - # df["ECO Eligibility"].isin( - # [ - # "eco4 (subject to ciga)", - # "failed ciga", - # "eco4 - passed ciga" - # ] - # ) - # ] - # insulated_assumed = df[df["walls"] == "Cavity wall, as built, insulated"].copy() - # # We convert date built to datetime - # try: - # insulated_assumed = insulated_assumed[~pd.isnull(insulated_assumed["date_built"])] - # insulated_assumed["year_built"] = pd.to_datetime(insulated_assumed["date_built"].astype(str)).dt.year - # as_built_insulated.append(insulated_assumed) - # except Exception as e: - # print("oh well") - # - # true_eco4_assets.append(true_eco4) - # ciga_dependent_assets.append(ciga_dependent) - # - # true_eco4_assets = pd.concat(true_eco4_assets) - # ciga_dependent_assets = pd.concat(ciga_dependent_assets) - # as_built_insulated = pd.concat(as_built_insulated) - # - # true_eco4_assets["walls"].value_counts(normalize=True) - # ciga_dependent_assets["walls"].value_counts(normalize=True) - # - # from recommendations.recommendation_utils import extract_insulation_thickness - # - # true_eco4_assets["roof_insulation_thickness"] = true_eco4_assets["roof"].apply( - # lambda x: extract_insulation_thickness(x) - # ) - # - # true_eco4_assets["e"] = true_eco4_assets.merge( - # pd.DataFrame(cleaned["roof-description"])[["original_description", "insulation_thickness"]], - # how="left", - # left_on="roof", - # right_on="original_description" - # ) - # - # true_eco4_assets["sap"].mean() - # - # true_eco4_assets["insulation_thickness"].isin( - # ["250", "150", "200", "100", "75", "50"] - # ).sum() / true_eco4_assets.shape[0] - # - # true_eco4_assets["insulation_thickness"].isin( - # ["100"] - # ).sum() / true_eco4_assets.shape[0] - # - # as_built_insulated.groupby("property_type")["ECO Eligibility"].value_counts(normalize=True) +# def analyse_ha_data(outputs, loader): +# """ +# The approach we take within this function is the following: +# For properties that have been identified by warmfront as eligible properties, characterise them by scheme. The +# characterisation can be broken down as the following: +# 1) The property has been identified by Warmfront and is eligible for ECO4/GBIS work, under the strictest criteria +# 2) The property has been identified by Warmfront, however it has a full cavity, and therefore would be subject to +# a CIGA check +# 3) The property has been identified by Warmfront, but the EPC shows that the property has more than 100mm loft +# insulation +# 4) The property has been identified by Warmfront, but doesn't look like a property that would likely qualify under +# any cirsumstances, given the available data +# +# Then, for any property that has NOT been identifid by Warmfront, we identify properties that look like they would +# qualify under the strictest criteria, and mark these as potential additional opportunities. +# +# :return: +# """ +# +# eco4_rate = 1710 +# gbis_rate = 600 +# # old_eco4_rate = 1456 +# old_gbis_rate = 432 +# +# epc_c_threshold = 80 +# scheme_map = { +# "ECO4": "ECO4", +# "AFFORDABLE WARMTH": "ECO4", +# "ECO4 A/W": "ECO4", +# "ECO4 GBIS (ECO+)": "GBIS" +# } +# +# ha_analysis_results = [] +# total_revenue_results = [] +# for ha_name, datasets in outputs.items(): +# inputs = [x for k, x in loader.data.items() if k == ha_name][0] +# +# results_df = datasets["results_df"].copy() +# +# analysis_data = inputs["asset_list"][['asset_list_row_id', "ECO Eligibility"]].rename( +# columns={"row_meaning": "asset_identification_status"} +# ).merge( +# results_df, +# how="left", +# right_on="row_id", +# left_on="asset_list_row_id" +# ) +# +# analysis_data["is_remaining"] = True +# +# n_sold_eco4 = 0 +# n_sold_gbis = 0 +# if not inputs["survey_list"].empty: +# # Merge on the survey list and signal everything that is remaining or not (i.e. anything that hasn't had +# # a survey) +# survey_list = inputs["survey_list"].copy() +# +# # TODO: TEMP +# scheme_column = survey_list.columns[0] +# # We clean up the survey list installation or cancelled +# survey_list["installed_or_cancelled_clean"] = survey_list["INSTALLED OR CANCELLED"].str.lower() +# # Remove all punctuation +# survey_list["installed_or_cancelled_clean"] = survey_list["installed_or_cancelled_clean"].str.replace( +# r'[^\w\s]', '', regex=True +# ) +# # Remove double spaces +# survey_list["installed_or_cancelled_clean"] = survey_list["installed_or_cancelled_clean"].str.replace( +# r'\s+', ' ', regex=True +# ) +# # Remove trailing spaces +# survey_list["installed_or_cancelled_clean"] = survey_list["installed_or_cancelled_clean"].str.strip() +# +# # Remap the values in the scheme column +# survey_list[scheme_column] = survey_list[scheme_column].replace(scheme_map) +# +# survey_list["installation_status"] = None +# survey_list["installation_status"] = np.where( +# survey_list["installed_or_cancelled_clean"].isin(["installed", "installed see notes"]), +# "installed", +# survey_list["installation_status"] +# ) +# survey_list["installation_status"] = np.where( +# survey_list["installed_or_cancelled_clean"].isin(["cancelled"]), +# "cancelled", +# survey_list["installation_status"] +# ) +# # Find partial installations +# survey_list["installation_status"] = np.where( +# survey_list["installed_or_cancelled_clean"].str.contains("still to be installed"), +# "partially installed", +# survey_list["installation_status"] +# ) +# # Find partial cancellations +# # TODO: We might have more indications of partial cancellations +# survey_list["installation_status"] = np.where( +# survey_list["installed_or_cancelled_clean"].isin(["loft cancelled"]), +# "partially cancelled", +# survey_list["installation_status"] +# ) +# +# # Finally, for other cases, we set the status to "in progress" +# survey_list["installation_status"] = survey_list["installation_status"].fillna("in progress") +# +# # We concatenate the scheme name with the installation status +# survey_list["installation_status"] = ( +# survey_list[scheme_column] + " - " + survey_list["installation_status"] +# ) +# +# # TODO: END TEMP +# +# survey_list_to_merge = survey_list[["asset_list_row_id", scheme_column]].copy() +# survey_list_to_merge["is_remaining"] = False +# analysis_data = analysis_data.drop(columns="is_remaining").merge( +# survey_list_to_merge, +# how="left", on="asset_list_row_id" +# ) +# analysis_data["is_remaining"] = analysis_data["is_remaining"].fillna(True) +# +# n_sold_eco4 = survey_list_to_merge[survey_list_to_merge[scheme_column] == "ECO4"].shape[0] +# n_sold_gbis = survey_list_to_merge[survey_list_to_merge[scheme_column] == "GBIS"].shape[0] +# +# # Take just remaining +# analysis_data = analysis_data[analysis_data["is_remaining"]] +# +# # Also, if the HA has started selling, we remove any that are still subject to ciga +# n_eco4_missed_subject_to_ciga = 0 +# if not inputs["survey_list"].empty: +# n_eco4_missed_subject_to_ciga = (analysis_data["ECO Eligibility"] == "eco4 (subject to ciga)").sum() +# analysis_data = analysis_data[analysis_data["ECO Eligibility"] != "eco4 (subject to ciga)"] +# +# ################################################################################################ +# # We take the properties that strictly qualified under eco +# ################################################################################################ +# +# eco4_identified = analysis_data[analysis_data["ECO Eligibility"] == "eco4"].copy() +# eco4_identified["identification_type"] = None +# eco4_identified["identification_type"] = np.where( +# (eco4_identified["eco4_eligible"] == True) & (eco4_identified["eco4_strict"] == True), +# "strict", +# eco4_identified["identification_type"] +# ) +# +# # For expansive, the property can be no higher than an EPC C +# eco4_identified["identification_type"] = np.where( +# (eco4_identified["eco4_eligible"] == True) & (eco4_identified["eco4_strict"] == False) & ( +# eco4_identified["sap"] <= epc_c_threshold +# ), +# "expansive", +# eco4_identified["identification_type"] +# ) +# ################################################################################################ +# # We take the properties dependent on CIGA +# ################################################################################################ +# +# ciga_dependent_identified = analysis_data[ +# analysis_data["ECO Eligibility"].isin( +# [ +# "eco4 (subject to ciga)", +# "eco4 - passed ciga" +# ] +# ) +# ].copy() +# +# # These are properties that show filled cavity +# ciga_dependent_identified["identification_type"] = None +# ciga_dependent_identified["identification_type"] = np.where( +# ciga_dependent_identified["eco4_message"].isin( +# [ +# "Perfect suitability", +# "Meets cavity and sap", +# "Fails cavity, meets loft, fails SAP", +# "Meets fabric, fails SAP check", +# "Meets cavity, loft borderline, meets sap", +# ] +# ) & (ciga_dependent_identified["sap"] <= epc_c_threshold), +# "strict", +# ciga_dependent_identified["identification_type"] +# ) +# +# ciga_dependent_identified["identification_type"] = np.where( +# ((ciga_dependent_identified["eco4_message"].isin(["Meets just cavity"])) | ( +# ciga_dependent_identified["walls"].isin(["Cavity wall, filled cavity"]) +# )) & ( +# (ciga_dependent_identified["sap"] <= epc_c_threshold) & +# pd.isnull(ciga_dependent_identified["identification_type"]) +# ), +# "expansive", +# ciga_dependent_identified["identification_type"] +# ) +# +# ################################################################################################ +# # We properties that qualified for gbis +# ################################################################################################ +# gbis_identified = analysis_data[analysis_data["ECO Eligibility"] == "gbis"].copy() +# gbis_identified["identification_type"] = None +# gbis_identified["identification_type"] = np.where( +# (gbis_identified["gbis_eligible"] == True) & (gbis_identified["sap"] < 69), +# "strict", +# gbis_identified["identification_type"] +# ) +# +# gbis_identified["identification_type"] = np.where( +# (gbis_identified["gbis_eligible"] == True) & (gbis_identified["sap"] <= epc_c_threshold) & ( +# pd.isnull(gbis_identified["identification_type"]) +# ), +# "expansive", +# gbis_identified["identification_type"] +# ) +# +# # Finally, we look at the properties that have not been identified by Warmfront +# not_identified = analysis_data[ +# analysis_data["ECO Eligibility"].isin( +# [ +# "not eligible" +# ] +# ) +# ].copy() +# +# surplus_eco4 = not_identified[ +# (not_identified["eco4_eligible"] == True) & (not_identified["eco4_message"].isin( +# ["Perfect suitability", "Meets cavity, loft borderline, meets sap", "Near perfect suitability"] +# )) +# ] +# +# surplus_gbis = not_identified[ +# (not_identified["gbis_eligible"] == True) & ( +# ~not_identified["asset_list_row_id"].isin(surplus_eco4["asset_list_row_id"].values) +# ) & (not_identified["sap"] < 69) & ( +# (not_identified["cavity_type"].isin(["empty", "partial insulation"])) | ( +# not_identified["walls"].str.contains("partial", case=False, na=False) +# ) +# ) +# ] +# surplus_gbis = surplus_gbis[surplus_gbis["is_estimated"] == False] +# +# # Output variables - the data was sent to us in December, but the remaining figures are +# # what was in November +# november_remaining = loader.december_figures[loader.december_figures["HA Name"] == ha_name] +# +# # ECO4 +# n_properties_remaining_in_asset_list = inputs["asset_list"].shape[0] +# november_eco4_remaining = max(november_remaining["ECO4 remaining"].values[0], 0) +# november_eco4_sold = november_remaining["No. of Tech surveys complete - Eco 4"].values[0] +# eco4_sales_since_november = n_sold_eco4 - november_eco4_sold +# +# n_warmfront_identified_eco4 = eco4_identified.shape[0] + ciga_dependent_identified.shape[0] +# eco4_of_which_identified_strict = ( +# eco4_identified[eco4_identified["identification_type"] == "strict"].shape[0] + +# ciga_dependent_identified[ciga_dependent_identified["identification_type"] == "strict"].shape[0] +# ) +# eco4_of_which_identified_expansive = ( +# eco4_identified[eco4_identified["identification_type"] == "expansive"].shape[0] + +# ciga_dependent_identified[ciga_dependent_identified["identification_type"] == "expansive"].shape[0] +# ) +# # GBIS +# n_warmfront_identified_gbis = gbis_identified.shape[0] +# november_gbis_remaining = max(november_remaining["GBIS remaining"].values[0], 0) +# november_gbis_sold = november_remaining["No. of Tech surveys complete - GBIS"].values[0] +# gbis_sales_since_november = n_sold_gbis - november_gbis_sold +# gbis_of_which_identified_strict = gbis_identified[gbis_identified["identification_type"] == "strict"].shape[0] +# gbis_of_which_identified_expansive = \ +# gbis_identified[gbis_identified["identification_type"] == "expansive"].shape[0] +# +# to_append = { +# ("", "HA Name"): ha_name, +# ("", "# properties in asset list"): n_properties_remaining_in_asset_list, +# ############ +# # ECO4 +# ############ +# ("ECO4", "# remaining November file"): november_eco4_remaining, +# ("ECO4", "# sold in November file"): november_eco4_sold, +# ("ECO4", "# sold (survey list)"): n_sold_eco4, +# ("ECO4", "# that missed CIGA check"): n_eco4_missed_subject_to_ciga, +# ("ECO4", "# Remaining properties (asset list)"): n_warmfront_identified_eco4, +# ("ECO4", "Of which identified by model - strict"): eco4_of_which_identified_strict, +# ("ECO4", "Of which identified by model - expansive"): eco4_of_which_identified_expansive, +# ("ECO4", "Of which identified by model - total"): ( +# eco4_of_which_identified_strict + eco4_of_which_identified_expansive +# ), +# ("ECO4", "Additional properties"): surplus_eco4.shape[0], +# ############ +# # GBIS +# ############ +# ("GBIS", "# remaining November file"): november_gbis_remaining, +# ("GBIS", "# sold in November file"): november_gbis_sold, +# ("GBIS", "# sold (survey list)"): n_sold_gbis, +# ("GBIS", "# Remaining properties (asset list)"): n_warmfront_identified_gbis, +# ("GBIS", "Of which identified by model - strict"): gbis_of_which_identified_strict, +# ("GBIS", "Of which identified by model - expansive"): gbis_of_which_identified_expansive, +# ("GBIS", "Of which identified by model - total"): ( +# gbis_of_which_identified_strict + gbis_of_which_identified_expansive +# ), +# ("GBIS", "Additional properties"): surplus_gbis.shape[0] +# } +# +# ha_analysis_results.append(to_append) +# +# # Calculate the revenue results +# to_append_revenue = { +# ("", "HA Name"): ha_name, +# # Eco4 revenue +# ("ECO4", "£ remaining November file"): november_eco4_remaining * eco4_rate, +# ("ECO4", "£ sold November file"): november_eco4_sold * old_eco4_rate, +# ("ECO4", "£ sold since November"): eco4_sales_since_november * eco4_rate, +# ("ECO4", "£ stuck at ciga check"): n_eco4_missed_subject_to_ciga * eco4_rate, +# ("ECO4", "£ remaining (asset list)"): n_warmfront_identified_eco4 * eco4_rate, +# ("ECO4", "Of which identified by model - strict"): eco4_of_which_identified_strict * eco4_rate, +# ("ECO4", "Of which identified by model - expansive"): eco4_of_which_identified_expansive * eco4_rate, +# ("ECO4", "Of which identified by model - total"): eco4_rate * ( +# eco4_of_which_identified_strict + eco4_of_which_identified_expansive +# ), +# ("ECO4", "Additional properties"): eco4_rate * surplus_eco4.shape[0], +# } +# total_revenue_results.append(to_append_revenue) +# +# ha_analysis_results = pd.DataFrame(ha_analysis_results) +# ha_analysis_results.columns = pd.MultiIndex.from_tuples(ha_analysis_results.columns) +# +# facts_and_figures = loader.facts_and_figures.copy() +# facts_and_figures["ha_number"] = facts_and_figures["HA Name"].str.extract(r'(\d+)').astype(int) +# facts_and_figures = facts_and_figures.sort_values("ha_number") +# facts_and_figures = facts_and_figures.drop(columns=["ha_number"]) +# +# # Rename some of the cols +# facts_and_figures = facts_and_figures.rename( +# columns={ +# # ECO4 cols +# "ECO4": "ECO4 - November", +# "GBIS": "GBIS - November", +# "eco4 (subject to ciga)": "ECO4 - subject to ciga", +# "eco4": "ECO4 - doesn't need CIGA", +# "eco4 - passed ciga": "ECO4 - passed CIGA", +# "failed ciga": "ECO4 - failed CIGA", +# "ECO4 - partially cancelled": "ECO4 - Install downgrade to GBIS", +# "ECO4 - in progress": "ECO4 - Install in progress", +# "ECO4 - cancelled": "ECO4 - Install cancelled", +# # GBIS cols +# "gbis": "GBIS total (asset list)" +# } +# ) +# # We calculate the eco4 total from the asset list +# # 1) If ciga checks have been completed (i.e. ECO4 - passed ciga > 0) this sum is +# # ECO4 - doesn't need CIGA + ECO4 - passed CIGA +# # 2) if ciga checks haven't been completed (i.e. ECO4 - passed ciga is missing), this sum is +# # ECO4 - doesn't need CIGA + ECO4 - subject to ciga +# facts_and_figures["ECO4 total (asset list - pre ciga)"] = ( +# facts_and_figures["ECO4 - doesn't need CIGA"] + +# facts_and_figures["ECO4 - subject to ciga"] + +# facts_and_figures["ECO4 - passed CIGA"] +# ) +# +# facts_and_figures["ECO4 total (asset list - post ciga)"] = None +# facts_and_figures["ECO4 total (asset list - post ciga)"] = np.where( +# facts_and_figures["ECO4 - passed CIGA"] > 0, +# facts_and_figures["ECO4 - doesn't need CIGA"] + facts_and_figures["ECO4 - passed CIGA"], +# facts_and_figures["ECO4 total (asset list - post ciga)"] +# ) +# +# # Re-arrange the columns +# facts_and_figures = facts_and_figures[ +# [ +# 'HA Name', +# 'ECO4 - November', +# 'GBIS - November', +# 'ECO4 total (asset list - pre ciga)', +# 'ECO4 total (asset list - post ciga)', +# 'GBIS total (asset list)', +# 'ECO4 - subject to ciga', +# "ECO4 - doesn't need CIGA", +# 'ECO4 - passed CIGA', +# 'ECO4 - failed CIGA', +# 'ECO4 - installed', +# 'ECO4 - Install in progress', +# 'ECO4 - Install cancelled', +# 'ECO4 - partially installed', +# 'ECO4 - Install downgrade to GBIS', +# ] +# ] +# # Addd a note to flag any rows where ECO4 ( +# # subject to ciga is greater than 0) and (ECO4 - passed ciga is greater than 0 +# # ) +# facts_and_figures["Missed CIGA checks opportunity"] = None +# facts_and_figures["Missed CIGA checks opportunity"] = np.where( +# (facts_and_figures["ECO4 - subject to ciga"] > 0) & (facts_and_figures["ECO4 - passed CIGA"] > 0), +# "potential opportunity of " + facts_and_figures["ECO4 - subject to ciga"].astype( +# str) + " ECO4 properties needing a CIGA check", +# facts_and_figures["Missed CIGA checks opportunity"] +# ) +# +# facts_and_figures.to_csv("Facts and figures sample.csv") +# +# # Re arrage the columns +# +# # Also sort ha_analysis_results by ha number +# ha_analysis_results["ha_number"] = ha_analysis_results[("", "HA Name")].str.extract(r'(\d+)').astype(int) +# ha_analysis_results = ha_analysis_results.sort_values("ha_number") +# ha_analysis_results = ha_analysis_results.drop(columns=["ha_number"]) +# +# # We save 2 sheets +# # Automate creation of the excel +# # Create a Pandas Excel writer using XlsxWriter as the engine +# with pd.ExcelWriter('HA Analysis Results.xlsx', engine='xlsxwriter') as writer: +# # Write each dataframe to a different worksheet without the index +# for df, sheet in [(facts_and_figures, 'HA Facts and Figures'), +# (ha_analysis_results, 'Asset Identification')]: +# +# df.to_excel(writer, sheet_name=sheet) +# +# # Auto-adjust columns' width +# for i, width in enumerate(get_col_widths(df)): +# writer.sheets[sheet].set_column(i, i, width) +# +# # Inspection: - Looking into the proportion of homes with "cavity, as built, insulated (assumed)" as their +# # description, and what proportion of time they get identified via non-invasive surveys +# +# # true_eco4_assets = [] +# # ciga_dependent_assets = [] +# # not_eligible = [] +# # as_built_insulated = [] +# # date_cols = { +# # "HA39": "date_built", +# # "HA14": "Built In Year", +# # "HA6": "Construction Year", +# # "HA1": "Build Date", +# # "HA107": "YEAR BUILT" +# # } +# # for ha_name, data_objects in outputs.items(): +# # inputs = [x for k, x in loader.data.items() if k == ha_name][0] +# # +# # date_col = date_cols[ha_name] +# # results_df = data_objects["results_df"].copy() +# # df = inputs["asset_list"][['asset_list_row_id', "ECO Eligibility", date_col]].rename( +# # columns={"row_meaning": "asset_identification_status", date_col: "date_built"} +# # ).merge( +# # results_df, +# # how="left", +# # right_on="row_id", +# # left_on="asset_list_row_id" +# # ) +# # +# # # take the true ECO4 +# # true_eco4 = df[df["ECO Eligibility"] == "eco4"].copy() +# # ciga_dependent = df[ +# # df["ECO Eligibility"].isin( +# # [ +# # "eco4 (subject to ciga)", +# # "failed ciga", +# # "eco4 - passed ciga" +# # ] +# # ) +# # ] +# # insulated_assumed = df[df["walls"] == "Cavity wall, as built, insulated"].copy() +# # # We convert date built to datetime +# # try: +# # insulated_assumed = insulated_assumed[~pd.isnull(insulated_assumed["date_built"])] +# # insulated_assumed["year_built"] = pd.to_datetime(insulated_assumed["date_built"].astype(str)).dt.year +# # as_built_insulated.append(insulated_assumed) +# # except Exception as e: +# # print("oh well") +# # +# # true_eco4_assets.append(true_eco4) +# # ciga_dependent_assets.append(ciga_dependent) +# # +# # true_eco4_assets = pd.concat(true_eco4_assets) +# # ciga_dependent_assets = pd.concat(ciga_dependent_assets) +# # as_built_insulated = pd.concat(as_built_insulated) +# # +# # true_eco4_assets["walls"].value_counts(normalize=True) +# # ciga_dependent_assets["walls"].value_counts(normalize=True) +# # +# # from recommendations.recommendation_utils import extract_insulation_thickness +# # +# # true_eco4_assets["roof_insulation_thickness"] = true_eco4_assets["roof"].apply( +# # lambda x: extract_insulation_thickness(x) +# # ) +# # +# # true_eco4_assets["e"] = true_eco4_assets.merge( +# # pd.DataFrame(cleaned["roof-description"])[["original_description", "insulation_thickness"]], +# # how="left", +# # left_on="roof", +# # right_on="original_description" +# # ) +# # +# # true_eco4_assets["sap"].mean() +# # +# # true_eco4_assets["insulation_thickness"].isin( +# # ["250", "150", "200", "100", "75", "50"] +# # ).sum() / true_eco4_assets.shape[0] +# # +# # true_eco4_assets["insulation_thickness"].isin( +# # ["100"] +# # ).sum() / true_eco4_assets.shape[0] +# # +# # as_built_insulated.groupby("property_type")["ECO Eligibility"].value_counts(normalize=True) def get_propensity_model_data( @@ -2567,29 +2567,39 @@ def calculate_eco4_post_ciga( eligiblity_counts["ECO Eligibility"] == "eco4 - passed ciga" ]["count"].sum() + eco4_confirmed_ciga_failures = eligiblity_counts[ + eligiblity_counts["ECO Eligibility"] == "failed ciga" + ]["count"].sum() + eco4_confirmed = (eco4_no_ciga_needed * ha_eco4_to_sale_rate) + (eco4_ciga_passed * ha_ciga_pass_to_sale_rate) eco4_confirmed = np.round(eco4_confirmed) if remaining_needing_ciga_check > 0: # We update the eco4 post ciga with the converted remaining + eco4_ciga_expected_remaining_to_pass = np.round(remaining_needing_ciga_check * ha_ciga_conversion_rate) eco4_remaining_forecast = np.round( - remaining_needing_ciga_check * ha_ciga_conversion_rate * ha_ciga_pass_to_sale_rate + eco4_ciga_expected_remaining_to_pass * ha_ciga_pass_to_sale_rate ) + eco4_estimated_ciga_failures = remaining_needing_ciga_check - eco4_ciga_expected_remaining_to_pass eco4_post_ciga = eco4_confirmed + eco4_remaining_forecast else: eco4_remaining_forecast = 0 + eco4_estimated_ciga_failures = 0 eco4_post_ciga = eco4_confirmed else: eco4_no_ciga_needed = eligiblity_counts[ eligiblity_counts["ECO Eligibility"] == "eco4" ]["count"].sum() + eco4_confirmed_ciga_failures = 0 + # Multiply by sale conversion eco4_confirmed = np.round(eco4_no_ciga_needed * ha_eco4_to_sale_rate) + eco4_ciga_expected_remaining_to_pass = np.round(remaining_needing_ciga_check * ha_ciga_conversion_rate) + eco4_estimated_ciga_failures = remaining_needing_ciga_check - eco4_ciga_expected_remaining_to_pass + eco4_remaining_forecast = np.round( - remaining_needing_ciga_check * ha_ciga_conversion_rate * ha_ciga_pass_to_sale_rate - ) - eco4_post_ciga = ( - eligiblity_counts[eligiblity_counts["ECO Eligibility"] == "eco4"]["count"].sum() + eco4_remaining_forecast + eco4_ciga_expected_remaining_to_pass * ha_ciga_pass_to_sale_rate ) + eco4_post_ciga = eco4_confirmed + eco4_remaining_forecast eco4_post_ciga = int(eco4_post_ciga) eco4_remaining_forecast = int(eco4_remaining_forecast) @@ -2604,6 +2614,16 @@ def calculate_eco4_post_ciga( "ECO4 - post CIGA - £": eco4_post_ciga * eco4_rate, "Of which confirmed - £": eco4_confirmed * eco4_rate, "Of which forecast - £": eco4_remaining_forecast * eco4_rate, + # Ciga failures + "Estimated total - failed CIGA": int(eco4_confirmed_ciga_failures + eco4_estimated_ciga_failures), + "Confirmed CIGA failures": eco4_confirmed_ciga_failures, + "Estimated CIGA failures": int(eco4_estimated_ciga_failures), + # Ciga failures cost + "Estimated total - failed CIGA - £": int( + (eco4_confirmed_ciga_failures + eco4_estimated_ciga_failures) * eco4_rate + ), + "Confirmed CIGA failures - £": int(eco4_confirmed_ciga_failures * eco4_rate), + "Estimated CIGA failures - £": int(eco4_estimated_ciga_failures * eco4_rate), } return results @@ -2617,8 +2637,8 @@ def forecast_remaining_sales(loader): gbis_rate = 600 eco4_rate = 1710 - old_gbis_rate = 432 - old_eco4_rate = 1456 + # old_gbis_rate = 432 + # old_eco4_rate = 1456 # 1) Calculate the conversion rate from passed CIGA to actual sale converted_ciga_jobs = [] @@ -2800,16 +2820,18 @@ def forecast_remaining_sales(loader): results = [] for ha_name, input_data in loader.data.items(): + # Original warmfront figures - ECO4 original_warmfront_estimates = december_figures[december_figures["HA Name"] == ha_name] original_warmfront_eco4 = original_warmfront_estimates["ECO4"].values[0] original_warmfront_remaining_eco4 = original_warmfront_estimates["ECO4 remaining"].values[0] - original_warmfront_eco4_revenue = ( - original_warmfront_remaining_eco4 * eco4_rate + - (original_warmfront_eco4 - original_warmfront_remaining_eco4) * old_eco4_rate - ) + # original_warmfront_eco4_revenue = ( + # original_warmfront_remaining_eco4 * eco4_rate + + # (original_warmfront_eco4 - original_warmfront_remaining_eco4) * old_eco4_rate + # ) + original_warmfront_eco4_revenue = original_warmfront_eco4 * eco4_rate original_warmfront_remaining_eco4_revenue = original_warmfront_remaining_eco4 * eco4_rate # Original warmfront figures - GBIS @@ -2817,9 +2839,12 @@ def forecast_remaining_sales(loader): original_warmfront_gbis = original_warmfront_estimates["GBIS"].values[0] original_warmfront_remaining_gbis = original_warmfront_estimates["GBIS remaining"].values[0] + # original_warmfront_gbis_revenue = ( + # original_warmfront_remaining_gbis * gbis_rate + + # (original_warmfront_gbis - original_warmfront_remaining_gbis) * old_gbis_rate + # ) original_warmfront_gbis_revenue = ( - original_warmfront_remaining_gbis * gbis_rate + - (original_warmfront_gbis - original_warmfront_remaining_gbis) * old_gbis_rate + original_warmfront_gbis * gbis_rate ) original_warmfront_remaining_gbis_revenue = original_warmfront_remaining_gbis * gbis_rate @@ -2835,6 +2860,7 @@ def forecast_remaining_sales(loader): how="left", on="asset_list_row_id" ) + # Anything that has an installation has gone to installation, and therefore is not remaining asset_list_remaining = asset_list_remaining[pd.isnull(asset_list_remaining["installation_status"])] asset_list_remaining = asset_list_remaining.drop(columns=["installation_status"]) @@ -2913,6 +2939,32 @@ def forecast_remaining_sales(loader): eco4_rate=eco4_rate ) + # GBIS Figures + # Estimate the GBIS conversion rate + ha_gbis_sale_conversion = gbis_ciga_independent_passrates[ + gbis_ciga_independent_passrates["Ha Name"] == ha_name + ] + + if not ha_gbis_sale_conversion.empty: + ha_gbis_sale_conversion = ( + ha_gbis_sale_conversion["# GBIS successfully installed"].values[0] / + ha_gbis_sale_conversion["# GBIS at install stage"].values[0] + ) + else: + ha_gbis_sale_conversion = median_gbis_to_install + + gbis_total = eligiblity_counts[ + eligiblity_counts["ECO Eligibility"] == "gbis" + ]["count"].sum() + gbis_total = np.round(gbis_total * ha_gbis_sale_conversion) + gbis_total_revenue = gbis_total * gbis_rate + + gbis_remaining = eligiblity_counts_remaining[ + eligiblity_counts["ECO Eligibility"] == "gbis" + ]["count"].sum() + gbis_remaining = np.round(gbis_remaining * ha_gbis_sale_conversion) + gbis_remaining_revenue = gbis_remaining * gbis_rate + to_append = { ("", "", "", "HA Name"): ha_name, # ECO4 - original warmfront figures @@ -2950,16 +3002,48 @@ def forecast_remaining_sales(loader): ("ECO4 post-ciga", "", "Of which forecast - £", ""): eco4_post_ciga_remaining_results["Of which forecast - £"], # CIGA failures + ("ECO4 CIGA failures", "", "Estimated total - failed CIGA - #", ""): eco4_post_ciga_remaining_results[ + 'Estimated total - failed CIGA' + ], + ("ECO4 CIGA failures", "", "Estimated total - failed CIGA - £", ""): eco4_post_ciga_remaining_results[ + 'Estimated total - failed CIGA - £' + ], + ("ECO4 CIGA failures", "", "Confirmed failures - #", ""): eco4_post_ciga_remaining_results[ + "Confirmed CIGA failures" + ], + ("ECO4 CIGA failures", "", "Confirmed failures - £", ""): eco4_post_ciga_remaining_results[ + "Confirmed CIGA failures - £" + ], + ("ECO4 CIGA failures", "", "Estimated failures - #", ""): eco4_post_ciga_remaining_results[ + "Estimated CIGA failures" + ], + ("ECO4 CIGA failures", "", "Estimated failures - £", ""): eco4_post_ciga_remaining_results[ + "Estimated CIGA failures - £" + ], + # GBIS postcode list + ("", "Warmfront post code list", "Total - #", "GBIS total"): gbis_total, + ("", "Warmfront post code list", "Remaining - #", "GBIS total"): gbis_remaining, + ("", "Warmfront post code list", "Total - £", "GBIS total"): gbis_total_revenue, + ("", "Warmfront post code list", "Remaining - £", "GBIS total"): gbis_remaining_revenue, } # Make sure nothing is forgotten due to duplicate multi-index keys - if len(to_append) != 22: + if len(to_append) != 32: raise ValueError("Something went wrong") results.append(to_append) results = pd.DataFrame(results) + # TODO: Add a blank row and then a total row + + assumptions = { + "ECO4 new rate": eco4_rate, + "GBIS new rate": gbis_rate, + # "ECO4 old rate": old_eco4_rate, + # "GBIS old rate": old_gbis_rate, + } + def app(): """