diff --git a/modules/ml-pipeline/src/README.md b/modules/ml-pipeline/src/README.md index d7afc6a..db1b8b4 100644 --- a/modules/ml-pipeline/src/README.md +++ b/modules/ml-pipeline/src/README.md @@ -1,3 +1,3 @@ -# The generic reproducible ML-pipeline +# The generic reproducible ML-pipeline! Pipeline required to build a model to produce an output, that gets hashed via DVC diff --git a/modules/ml-pipeline/src/pipeline/.gitignore b/modules/ml-pipeline/src/pipeline/.gitignore index bf035d2..ce8309f 100644 --- a/modules/ml-pipeline/src/pipeline/.gitignore +++ b/modules/ml-pipeline/src/pipeline/.gitignore @@ -1,3 +1,4 @@ # Ignore dynaconf secret files .secrets.* +example.py diff --git a/modules/ml-pipeline/src/pipeline/configs/feature_processor_logic.py b/modules/ml-pipeline/src/pipeline/configs/feature_processor_logic.py index 103168d..bcc53e5 100644 --- a/modules/ml-pipeline/src/pipeline/configs/feature_processor_logic.py +++ b/modules/ml-pipeline/src/pipeline/configs/feature_processor_logic.py @@ -18,30 +18,44 @@ def remove_starting_columns(df): return df -def remove_floor_height_ending(df): - # df.describe(percentiles=[0.005,0.99])['FLOOR_HEIGHT_ENDING'] - # shows bottom 0.5 percentile is 1.665 - # So keep anything above this - df = df[df["floor_height_ending"] > 1.665].reset_index(drop=True) - print("we in here") +def keep_negative_heat_change(df): + df = df[df["heat_demand_change"] < 0] return df -def remove_minimum_habitable_room_size(df): - # Need minimum of 6.5m per habitable room - df = df[ - df["total_floor_area_ending"] / df["number_habitable_rooms"] > 6.5 - ].reset_index(drop=True) +def keep_non_negative_carbon_ending(df): + df = df[df["carbon_ending"] > 0] return df -def keep_flats(df): - df = df[df["property_type"] == "Flat"] +def keep_negative_carbon_change(df): + df = df[df["carbon_change"] < 0] return df -def keep_non_zero_rdsap(df): - df = df[df["rdsap_change"] != 0] +# TODO: Move to ETL pipeline +def remove_unreasonable_habitable_rooms(df): + """ + Assumption is that proportion of floor area to habitable rooms should be at least 6.5m2 + """ + minimum_room_size_index = ( + df["total_floor_area_ending"] / df["number_habitable_rooms"] >= 6.5 + ) + df = df[minimum_room_size_index] + return df + + +def remove_top_1_percent_heat_demand(df): + # threshold_value = df.describe(percentiles=[0.99])['HEAT_DEMAND_STARTING']['99%'] + threshold_value = 860 + df = df[df["heat_demand_starting"] < threshold_value] + return df + + +def remove_top_1_percent_carbon(df): + # threshold_value = df.describe(percentiles=[0.99])['CARBON_STARTING']['99%'] + threshold_value = 18 + df = df[df["carbon_starting"] < threshold_value] return df @@ -54,10 +68,12 @@ def keep_non_zero_rdsap(df): # return df business_logic = { - # "keep_non_zero_rdsap": keep_non_zero_rdsap, - # "keep_flats": keep_flats, - # "remove_minimum_habitable_room_size": remove_minimum_habitable_room_size, - # "remove_floor_height_ending": remove_floor_height_ending + "remove_unreasonable_habitable_rooms": remove_unreasonable_habitable_rooms, + "keep_negative_heat_change": keep_negative_heat_change, + "keep_negative_carbon_change": keep_negative_carbon_change, + "remove_top_1_percent_heat_demand": remove_top_1_percent_heat_demand, + "remove_top_1_percent_carbon": remove_top_1_percent_carbon, + "keep_non_negative_carbon_ending": keep_non_negative_carbon_ending, # "remove_starting_columns": remove_starting_columns # "keep_ENDING_COLUMNS": keep_ending_columns } diff --git a/modules/ml-pipeline/src/pipeline/configs/post_prediction_logic.py b/modules/ml-pipeline/src/pipeline/configs/post_prediction_logic.py index 643231a..2ca8890 100644 --- a/modules/ml-pipeline/src/pipeline/configs/post_prediction_logic.py +++ b/modules/ml-pipeline/src/pipeline/configs/post_prediction_logic.py @@ -1,23 +1,24 @@ """ After predictions, we may want to apply some post processing to the predictions """ + import pandas as pd def clip_predictions_to_minimum_value( - data: pd.DataFrame, predictions: pd.Series, minimum_value: int = 0 + data: pd.DataFrame, + predictions: pd.Series, ) -> pd.Series: series_name = predictions.name predictions.name = "predictions" + predictions = predictions.astype(data["carbon_starting"].dtype) predictions_df = pd.concat([data, predictions], axis=1) # We expect all prediction to be atleast one point improvement - replace_index = ( - predictions_df["sap_starting"] + minimum_value > predictions_df["predictions"] - ) - predictions_df.loc[replace_index, "predictions"] = ( - predictions_df.loc[replace_index, "sap_starting"] + minimum_value - ) + replace_index = predictions_df["predictions"] > predictions_df["carbon_starting"] + predictions_df.loc[replace_index, "predictions"] = predictions_df.loc[ + replace_index, "carbon_starting" + ] predictions_new = predictions_df["predictions"] predictions_new.name = series_name diff --git a/modules/ml-pipeline/src/pipeline/configs/settings.yaml b/modules/ml-pipeline/src/pipeline/configs/settings.yaml index 838e9a9..d173b56 100644 --- a/modules/ml-pipeline/src/pipeline/configs/settings.yaml +++ b/modules/ml-pipeline/src/pipeline/configs/settings.yaml @@ -31,13 +31,14 @@ default: feature_processor_config: subsample_amount: null subsample_seed: 0 - target: sap_ending + target: carbon_ending identifier_columns: ["uprn"] - # drop_columns: ["heat_demand_change", "carbon_change", "rdsap_change", "heat_demand_ending", "carbon_ending", "days_to_starting", "days_to_ending"] + # drop_columns: ["heat_demand_change", "carbon_change", "rdsap_change", "heat_demand_ending", "sap_ending"] drop_columns: [ - "heat_demand_change", "carbon_change", "rdsap_change", "heat_demand_ending", "carbon_ending", "days_to_starting", "days_to_ending", + "heat_demand_change", "carbon_change", "rdsap_change", "heat_demand_ending", "sap_ending", "days_to_starting", "days_to_ending", 'number_habitable_rooms_starting', 'number_habitable_rooms_ending', 'number_heated_rooms_starting', 'number_heated_rooms_ending', 'number_habitable_rooms', 'number_heated_rooms'] + # retain_features: ["SAP_STARTING", "TOTAL_FLOOR_AREA_DIFF"] retain_features: null # retain_features: ['uprn', 'sap_starting', 'hot_water_energy_eff_ending', # 'mainheat_energy_eff_ending', 'constituency', 'roof_energy_eff_ending', diff --git a/modules/ml-pipeline/src/pipeline/dvc.lock b/modules/ml-pipeline/src/pipeline/dvc.lock deleted file mode 100644 index 31315db..0000000 --- a/modules/ml-pipeline/src/pipeline/dvc.lock +++ /dev/null @@ -1,190 +0,0 @@ -schema: '2.0' -stages: - startup_cleanup: - cmd: python 0_startup_cleanup.py - deps: - - path: 0_startup_cleanup.py - hash: md5 - md5: b1b12f6b6393fbf8b83d23684df0a3d4 - size: 1220 - params: - configs/settings.yaml: - default.startup_cleanup.artefacts: ./data - default.startup_cleanup.metrics: ./metrics - prepare_data: - cmd: python 1_prepare_data.py - deps: - - path: 1_prepare_data.py - hash: md5 - md5: 11a3b8bfdfe199ab7ecc39ccc5652649 - size: 4298 - params: - configs/settings.yaml: - default.feature_processor.feature_processor_config.drop_columns: - - heat_demand_change - - carbon_change - - rdsap_change - - heat_demand_ending - - carbon_ending - - days_to_starting - - days_to_ending - - number_habitable_rooms_starting - - number_habitable_rooms_ending - - number_heated_rooms_starting - - number_heated_rooms_ending - - number_habitable_rooms - - number_heated_rooms - default.feature_processor.feature_processor_config.retain_features: - default.feature_processor.feature_processor_config.subsample_amount: - default.feature_processor.feature_processor_config.subsample_seed: 0 - default.feature_processor.feature_processor_config.target: sap_ending - default.feature_processor.feature_processor_type: dataframe - default.prepare_data.data_filepath: - s3://retrofit-data-dev/sap_change_model/2024-05-28-19-08-25/dataset_rooms.parquet - default.prepare_data.input_dataclient_type: aws-s3 - default.prepare_data.output_dataclient_type: local - default.prepare_data.output_test_filepath: ./data/prepared_data/test.parquet - default.prepare_data.output_train_filepath: ./data/prepared_data/train.parquet - default.prepare_data.train_proportion: 0.9 - outs: - - path: data/prepared_data/ - hash: md5 - md5: 80c9e138146a1d96b9d16091c207e2e8.dir - size: 45056059 - nfiles: 2 - build_model: - cmd: python 2_build_model.py - deps: - - path: 2_build_model.py - hash: md5 - md5: 7231450b78920b0c5e7c6bada496b24a - size: 4820 - - path: data/prepared_data - hash: md5 - md5: 80c9e138146a1d96b9d16091c207e2e8.dir - size: 45056059 - nfiles: 2 - params: - configs/build_model.yaml: - default: - build_model: - model_type: AutogluonAutoML - model_save_filepath: ./data/model/optimised/ - fit_metrics_filepath: ./metrics/fit_metrics.json - fit_predictions_filepath: ./data/fit_predictions/predictions.parquet - SKLearnLinearRegression: - SKLearnSVMRegression: - kernel: linear - AutogluonAutoML: - output_filepath: ./data/model/allmodels/ - problem_type: regression - eval_metric: mean_squared_error - time_limit: 1800 - presets: medium_quality - excluded_model_types: - - RF - - CAT - - NN_TORCH - - KNN - - XT - infer_limit: 0.05 - infer_limit_batch_size: 10000 - ag_args_ensemble: - num_folds_parallel: 2 - outs: - - path: data/fit_predictions/ - hash: md5 - md5: d9c9afc05e8780db47c0548b19bf7d19.dir - size: 3349989 - nfiles: 1 - - path: data/model/ - hash: md5 - md5: 13c3100e1486c27a83a8a47491077842.dir - size: 773523079 - nfiles: 36 - - path: metrics/fit_metrics.json - hash: md5 - md5: 2ff70a2a45813e1bcdf2ea3aa8e07d4a - size: 224 - generate_predictions: - cmd: python 3_generate_predictions.py - deps: - - path: 3_generate_predictions.py - hash: md5 - md5: 0a70ad4dfe99414a75d1261c75a177b9 - size: 2464 - - path: data/model - hash: md5 - md5: 13c3100e1486c27a83a8a47491077842.dir - size: 773523079 - nfiles: 36 - - path: data/prepared_data - hash: md5 - md5: 80c9e138146a1d96b9d16091c207e2e8.dir - size: 45056059 - nfiles: 2 - params: - configs/settings.yaml: - default.generate_predictions.input_dataclient_type: local - default.generate_predictions.output_dataclient_type: local - default.generate_predictions.predictions_column_name: predictions - default.generate_predictions.predictions_output_filepath: ./data/predictions/predictions.parquet - default.generate_predictions.test_data_filepath: ./data/prepared_data/test.parquet - outs: - - path: data/predictions/ - hash: md5 - md5: 5d07bcebf3160a72bb18dfd79106e85c.dir - size: 463197 - nfiles: 1 - generate_metrics: - cmd: python 4_generate_metrics.py - deps: - - path: 4_generate_metrics.py - hash: md5 - md5: 4fedb86d89d528f0a6597934ba3890a0 - size: 3484 - - path: data/predictions - hash: md5 - md5: 5d07bcebf3160a72bb18dfd79106e85c.dir - size: 463197 - nfiles: 1 - - path: data/prepared_data - hash: md5 - md5: 80c9e138146a1d96b9d16091c207e2e8.dir - size: 45056059 - nfiles: 2 - params: - configs/settings.yaml: - default.generate_metrics.dataclient_type: local - default.generate_metrics.metrics_output_filepath: ./metrics/metrics.json - default.generate_metrics.metrics_type: Regression - outs: - - path: metrics/metrics.json - hash: md5 - md5: 3e08df02fd5c5d094bcf936e1338d596 - size: 223 - generate_scenerio_metrics: - cmd: python 5_generate_scenarios.py - deps: - - path: 5_generate_scenarios.py - hash: md5 - md5: 40506749fefd926d47c60ff5b16db307 - size: 5337 - params: - configs/scenarios.yaml: - default.scenarios: - input_dataclient_type: aws-s3 - output_dataclient_type: local - scenario_data_filepaths: - - s3://retrofit-data-dev/scenario_data/28-05-2024-19-22-41/recommendations_scoring_data.parquet - comparison_output_filepath: ./metrics/scenario_table.md - metrics_output_filepath: ./metrics/scenario_metrics.md - outs: - - path: metrics/scenario_metrics.md - hash: md5 - md5: fa4d6d7bbd7818613800da5f8f37ea96 - size: 363 - - path: metrics/scenario_table.md - hash: md5 - md5: d6baf100a1623cc2467c2f8221d314c9 - size: 2133