From f7506039d2917a7306b39131c77a7b5ec73db8c1 Mon Sep 17 00:00:00 2001 From: Eseroghene Oghojafor Date: Sat, 14 Jun 2025 10:27:08 +0100 Subject: [PATCH 1/5] Finished Water Quality Evaluation --- .gitignore | 3 +- results/results.csv | 6 +++ src/clean_data.py | 19 +++++++--- src/evaluate.py | 89 +++++++++++++++++++++++++++++++++++++++++++-- src/load_data.py | 13 ++----- src/main.py | 25 +++++++++++++ 6 files changed, 135 insertions(+), 20 deletions(-) create mode 100644 results/results.csv diff --git a/.gitignore b/.gitignore index fa30cb2fb..8f47d5cb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ index.py -env/ \ No newline at end of file +env/ +venv diff --git a/results/results.csv b/results/results.csv new file mode 100644 index 000000000..466868dab --- /dev/null +++ b/results/results.csv @@ -0,0 +1,6 @@ +sensor_id,location,ph,turbidity,temperature +1,Lake A,6.48,2.43,21.81 +2,Lake B,7.04,4.39,18.51 +3,Lake C,6.69,3.78,20.96 +4,Lake D,6.5,2.42,22.22 +5,Lake E,7.75,2.72,21.26 diff --git a/src/clean_data.py b/src/clean_data.py index da613640a..828a4478b 100644 --- a/src/clean_data.py +++ b/src/clean_data.py @@ -1,7 +1,14 @@ -def clean_sensor_data(df: pd.DataFrame) -> pd.DataFrame: - """ - Clean sensor data by handling missing or invalid values. +import pandas as pd - Returns: - pd.DataFrame: Cleaned data. - """ +# Function to clean sensor data by converting 'pH' and 'turbidity' columns to numeric values. +def clean_sensor_data(df): + df['pH'] = pd.to_numeric(df['pH'], errors='coerce') + df['turbidity'] = pd.to_numeric(df['turbidity'], errors='coerce') + return df + +# Function to assign unique sensor IDs and lake locations to each row in the dataset. +def assign_sensor_and_location(df): + df = df.copy() + df['sensor'] = [f"Sensor {str(i+1).zfill(3)}" for i in range(len(df))] + df['location'] = [f"Lake {chr(65 + i)}" for i in range(len(df))] + return df \ No newline at end of file diff --git a/src/evaluate.py b/src/evaluate.py index 006256224..ac60dddeb 100644 --- a/src/evaluate.py +++ b/src/evaluate.py @@ -1,9 +1,90 @@ +# Importing necessary module +import pandas as pd +import os +import csv + +# Class for evaluating water quality based on pH and turbidity thresholds class WaterQualityEvaluator: def __init__(self, ph_range=(6.5, 8.5), turbidity_threshold=1.0): self.ph_range = ph_range self.turbidity_threshold = turbidity_threshold - def is_safe(self, row: pd.Series) -> bool: - """ - Determine if a row of water data is safe. - """ + def is_safe(self, pH, turbidity): + if pd.isna(pH): + return (False, "missing pH") + if pd.isna(turbidity): + return (False, "missing turbidity") + if pH < self.ph_range[0]: + return (False, "pH too low") + if pH > self.ph_range[1]: + return (False, "pH too high") + if turbidity > self.turbidity_threshold: + return (False, "turbidity too high") + + return (True, "Safe") + +# Evaluates each sensor's data and saves the results to a CSV file +def evaluate_and_save_results(df, output_path, show_top_n=5): + evaluator = WaterQualityEvaluator() + results = [] + safe_count = 0 + unsafe_count = 0 + + print("\nšŸ”Ž Evaluation Summary:\n") + + # Evaluate all sensor readings + for idx, row in df.iterrows(): + sensor = row['sensor'] + sensor_id = int(sensor.split()[-1]) + location = row['location'] + pH = row.get('pH') + turbidity = row.get('turbidity') + temperature = row.get('temperature', '') + + is_safe, reason = evaluator.is_safe(pH, turbidity) + status = "āœ… Safe" if is_safe else f"āŒ Unsafe ({reason})" + + if is_safe: + safe_count += 1 + else: + unsafe_count += 1 + + results.append({ + "sensor": sensor, # needed just for preview + "status": status, # needed just for preview + "sensor_id": sensor_id, + "location": location, + "ph": pH, + "turbidity": turbidity, + "temperature": temperature, + }) + + # Printing evaluation summary + print(f"Total Sensors Evaluated: {len(results)}") + print(f"āœ… Safe Sensors: {safe_count}") + print(f"āŒ Unsafe Sensors: {unsafe_count}\n") + + # Printing top N results as a preview + print(f" Preview of Top {show_top_n} Results:\n") + for entry in results[:show_top_n]: + print(f"{entry['sensor']} at {entry['location']}: {entry['status']}") + + #Saving only the top N results to CSV (without preview fields) + export_results = [ + { + "sensor_id": r["sensor_id"], + "location": r["location"], + "ph": r["ph"], + "turbidity": r["turbidity"], + "temperature": r["temperature"], + } + for r in results[:show_top_n] + ] + + os.makedirs(os.path.dirname(output_path), exist_ok=True) + with open(output_path, "w", newline="") as f: + writer = csv.DictWriter(f, fieldnames=["sensor_id", "location", "ph", "turbidity", "temperature"]) + writer.writeheader() + writer.writerows(export_results) + + print(f"\nTop {show_top_n} results saved to '{output_path}'") \ No newline at end of file diff --git a/src/load_data.py b/src/load_data.py index c0126703a..cbe21072b 100644 --- a/src/load_data.py +++ b/src/load_data.py @@ -1,10 +1,5 @@ -def load_csv(filepath: str) -> pd.DataFrame: - """ - Load sensor data from a CSV file. +import pandas as pd - Args: - filepath (str): Path to the CSV file. - - Returns: - pd.DataFrame: Loaded data as a pandas DataFrame. - """ +# Function to load a CSV file into a Pandas DataFrame +def load_csv(filepath): + return pd.read_csv(filepath) \ No newline at end of file diff --git a/src/main.py b/src/main.py index e69de29bb..c9ff09fd7 100644 --- a/src/main.py +++ b/src/main.py @@ -0,0 +1,25 @@ +# Import necessary functions from custom modules +from load_data import load_csv +from clean_data import clean_sensor_data, assign_sensor_and_location +from evaluate import evaluate_and_save_results + + +# Main Execution: Load, Clean, Label, and Filter Water Quality Data +if __name__ == "__main__": + df_raw = load_csv("/Users/eserogheneoghojafor/water_quality_monitoring/data/sensor_data.csv") + df_clean = clean_sensor_data(df_raw) + df_with_labels = assign_sensor_and_location(df_clean) + + lake_choice = input("Enter the lake you want to evaluate (e.g. 'Lake A'), or press Enter to evaluate all lakes: ").strip() + + if lake_choice: + df_selected = df_with_labels[df_with_labels['location'] == lake_choice] + if df_selected.empty: + print(f"No data found for '{lake_choice}'. Exiting.") + exit() + else: + df_selected = df_with_labels + + output_path = "/Users/eserogheneoghojafor/water_quality_monitoring/results/results.csv" + + evaluate_and_save_results(df_selected, output_path, show_top_n=5) \ No newline at end of file From e9dc0180a8f1d73246e6050eb1607223a0e78583 Mon Sep 17 00:00:00 2001 From: Eseroghene Oghojafor Date: Sat, 14 Jun 2025 10:38:48 +0100 Subject: [PATCH 2/5] Finished Water Quality Evaluation Project --- src/evaluate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.py b/src/evaluate.py index ac60dddeb..c8c3a4573 100644 --- a/src/evaluate.py +++ b/src/evaluate.py @@ -50,8 +50,8 @@ def evaluate_and_save_results(df, output_path, show_top_n=5): unsafe_count += 1 results.append({ - "sensor": sensor, # needed just for preview - "status": status, # needed just for preview + "sensor": sensor, + "status": status, "sensor_id": sensor_id, "location": location, "ph": pH, From cf6b743a1abd95b1385e3b5ad297947b33957e95 Mon Sep 17 00:00:00 2001 From: Eseroghene Oghojafor Date: Sat, 14 Jun 2025 12:04:45 +0100 Subject: [PATCH 3/5] Finished Water Quality Evaluation Project --- src/__pycache__/clean_data.cpython-312.pyc | Bin 0 -> 1297 bytes src/__pycache__/evaluate.cpython-312.pyc | Bin 0 -> 3769 bytes src/__pycache__/load_data.cpython-312.pyc | Bin 0 -> 365 bytes src/clean_data.py | 5 +++++ src/evaluate.py | 17 ++++++++--------- 5 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 src/__pycache__/clean_data.cpython-312.pyc create mode 100644 src/__pycache__/evaluate.cpython-312.pyc create mode 100644 src/__pycache__/load_data.cpython-312.pyc diff --git a/src/__pycache__/clean_data.cpython-312.pyc b/src/__pycache__/clean_data.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2c6db561a5162025749c97fe568aeeba6aae3ba GIT binary patch literal 1297 zcmb7EO=uHQ5Pom}nzp7@W7@R%6Ms;nU=)#pmSRJM`WMkskU|^Q-PdGevK!xS(WVKc z;H46vagCHJy6YE7!&f8@DDS~xiXEO8Vo0&KJZQgjj zH3%fubusygL+B%OTmj#awE&ngq#_lkQ8!k(+o+pUdC>d-4hgF)DW+g2x2yy(JUnZQ zpvF)hrG7sx=b)L2Eg*~KI+9|@b&`j^O%PMLC;UuhCKhXj*guiNUy#Cvkm6sEB17g; zCkjb1o6C0Cl4205kPx;dLa9MbyV~lf*EChL2JBjkWU_?H5FsJn78D~p04UY2v5dIh zpCMFJ0LiI+CRU46kzNHu`T0e?4NhH}>sV|!1M$J3ODloqhu#Tq>Du&;`TZ>~ zJd1&|a8Q^R{2yw)#j|VB0sX-S4+I=G9E5BB4;w6z)nbxIGZhB8Hi|~D!X=Qx_3S~Y zfK_Z&m2)8*IGO{;%}rIiC%>%9yQh=r0XNFs-6ue;0tRNSL3NdV<(|n&>ufTGSSEeOfwg^GcG2IJ$}DV9jLTQZPup%x#uUQ%mUa3Tb3r zjk{Ipc1Wm)#~cLp2YFUboqp|maphIxv$iGQxmo#M;=WSaU231&JDGf_Pw3N^-|Y;) z-Enkb+pz`TIbg}Hp$jV~PCh?AN1wGk?OpOmXYsfQm_4N%Q~M{ckM}Gz9A5B8Au~4= zTV{0n_C-Y7&f{;kKWehoJ~|Mo5ndh&MCyf*U`tt;R5mI56LU!J4Eq>SHm`HD@1E9- iq4uXq8{Gvlwn=j@y?RrT&;el<6!V>281W$A+{~`DxD`dw@`) z9`L>A-t)ZYoO|c|)#u|8z#q??oBV?Zp>OcQ0lI-~ya7lBNk}5nXq2#La+I`ZYLp_; zFp|h?NTTkLb%{}0VkG(+G0MymarOz`JU><^)yD=O+K9rsf@E7OXrv_qq$sRyl%A#H zjMaKc)MfR@IWe8oXTN_%Oy@*hQOBqq+ORUb-Vk7@AcHVa0CKCDBo~JwF z&^c_n8HPDzMuZ~0;4^!U7wLzbumPLsg(zST?I^4PQbGFGnNv=%u}A|9;!cCEF$N(K zQ+;qyVwU_rQsfRPa!ZQB5l=bA;+TM0BHCe`0{ftwekm7Ya}C*CEY4R7$9)$})#b$ck`{&Nlk+g3yLZvGZ5mWBxFxxO6MMwtyE(MK6_fw6-7uZGf!|V@Sdl! zH<_H6#OszV37fUPebJ&Xh~sjcw#ckx(Mc^MZWl_NQgPCNblP%nNjv4Ex-rd_)DjwK z$an3X{RY_!yxIf|b7;-uyMAK+MCsLqlhyr;#IJkJ;A_s_cUC=Ji|tF|=P@%lXnK4l zy5cMQs^W4$c;FGtVBa2lanlnj>5tk5mfHp%cm~YiD`r!d3fCXO<%pBmC_wbB2GZ>y z>!;vGLiJ|EX*rRw_yknBluKjWo3JatPEqljq6T639kSKh2Ul^4*n@qg@cFKx4U%L| zY;YbXR%gUKFVr>m%C74OkapJf9Ux#RP!p&C4@ZH4AFE?t8>FpjB@omURw~qa^!EmQ=>UM!6FVUFaxf=x@G}tv=@EBYQ`@ah$c8k~h z5)RiEhwmjEoaA<%+k)SqQodbAU}<;_pTlFHuBi|(np9HaGmPXh0ymN5y-gLGVUIN! z$(IKm1t!B7Yy)QvI@Pp?UboR~@P-HLH~fN zH#@ik2J=!{v%!MDEw?F03$fEq&>(>t+DSEN2^nM*L3U$su9j^(MoT@zAkhlAoh!h@ zfVbgHf)C8Ll?8!D+q$j?$KZa9k(Yt75Hx~P1WUkdYk|4Fv350P4$o5b7E>k{I%re~ z6@ogx88)Os4z@k(Ee@UvJJ|M|!s>Rx_G>P6-0gHS4)N)57~zfYlH7M=cN(|j7%H^t zT@Ez`@!1VV>jZfHIdONNqpuJ)!l~}vd{Fm|Ex2XjRL}p?jnH;1p=E$SN8<|_6zmLk z8w6xx|IYZ&LbM6^6@oLU2OUKkF$3!l5dnV--B+m((F_sqseco4xS!zHKl}6(q0uWO zm5gv9H$5$?vxB_FYH~(X)F=M|u(-4`ChEYT;u=+P*e#DPPiJLSgr{4!P!7N4U*Gz< zfFJxEez3m2y&$}w!LPT_w@JiReCy&a6(ma9D?z)jgQc`gO;9D?hD_1*Vm2bbO z=we#9U^}8YZpzZ2ki#B0)*J@d#x=6TZbNcV*d+LTK=_d=UrEX{f-){#RI);z7v7V# zTw2!#`8+L%x{xOa1$7_jPz5~T491x{j@`32w*9*pCoE3Bn$+}!GG!4nuykeQnRGHE z1Imvl<+Ow!c`eWIw!NSLT@$t^XyO%Ff)Az8yGiuMTkMzKVzSTz=@yrS-bhtuG>gJZ zM$1A!XHgTfZhs~$R?KGQjAT)1Ib)HEW^vQvlq@Ax&7!lSK54lC$964R0Y-}&)2>+j zP;yMaq+->UX9mxcvM9mAZ7;C7c$-B^Dio~uvPKUC7Z}t?nYmxsFtg7 z4vWX>O^hiyaMYW#ligTRN$ILZfnGb|J7Tz1Kz5EBM^a@`gW|%Ww-`C2tFsoNT7LOz zR#EkYV~rTM*t)w~8*oCCxfj$shjyonOo$l?dWb8sqedMDSzP?u2k;q#jv;VhCD1$f z1JfUv8#bF;=FXVG(A?R7(C!-Fw@Sy?S=8EA87Yta>fBQlVLbC(kt$v=n?t1!%3Vcv zE!0+JKl9%3-t;f3%aKDXq5h)V42Dbj@~I+c`U2N4&0i{A{N?2$X@=S=!{y=X$V#XW zc*5AHX3Z-zVZfBSxDg3Xo?Mmi3D+r&lq zeQ; zeDFl=z#I3;`^UbF{QgvJaHQrx`;a@gPGN!d2x@6>sQ6d2JIt;Jkk7yFL(z`v$r~{< z(q27u!)LYxOGD*evps5Wc63%RFL(5Bcvv^TPJz(e`E>--voK;@zZm)1$fsn*Rd!XH z%1w)&mB8V9`a}B7HMg%gRef!VTy^)aBZ`SHeZ1Bjs>I5%MdHDc@)t_~&eZh<%G-cy{m<@eX0j{}&ajaK8Wm literal 0 HcmV?d00001 diff --git a/src/__pycache__/load_data.cpython-312.pyc b/src/__pycache__/load_data.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..222d2572b73f10f84d407f4288cbc6014beb71d9 GIT binary patch literal 365 zcmX|5u};G<5WP#P5-1sf9|&UvA|Fu1#7Y;$(j~HDw@H=8!FGX43`npr!Pal6_!JnB z*a9098&bAToTHQ{-Me?b=V!nA{uU744$jhh>fd%)!)ZmmOJV^WIOZ@!?mWQInPcew zSi>N})@PgBR((if0p@=kt!?3kyc5ROUmTTu%mKbdCf#G zD34M*RCJ6fmcRZDRmWva$ WO{4v%_KAL7MEr!kx{J8q*#7{BfKe#` literal 0 HcmV?d00001 diff --git a/src/clean_data.py b/src/clean_data.py index 828a4478b..9c07c4bf2 100644 --- a/src/clean_data.py +++ b/src/clean_data.py @@ -2,8 +2,13 @@ # Function to clean sensor data by converting 'pH' and 'turbidity' columns to numeric values. def clean_sensor_data(df): + df = df.copy() + + # Convert to numeric, coercing invalid values to NaN df['pH'] = pd.to_numeric(df['pH'], errors='coerce') df['turbidity'] = pd.to_numeric(df['turbidity'], errors='coerce') + df['temperature'] = pd.to_numeric(df['temperature'], errors='coerce') + return df # Function to assign unique sensor IDs and lake locations to each row in the dataset. diff --git a/src/evaluate.py b/src/evaluate.py index c8c3a4573..d64ec175e 100644 --- a/src/evaluate.py +++ b/src/evaluate.py @@ -9,20 +9,19 @@ def __init__(self, ph_range=(6.5, 8.5), turbidity_threshold=1.0): self.ph_range = ph_range self.turbidity_threshold = turbidity_threshold - def is_safe(self, pH, turbidity): - if pd.isna(pH): - return (False, "missing pH") - if pd.isna(turbidity): - return (False, "missing turbidity") + def is_safe(self, pH, turbidity): + if pd.isna(pH) or pH == 0: + return (False, "missing or invalid pH") + if pd.isna(turbidity) or turbidity == 0: + return (False, "missing or invalid turbidity") if pH < self.ph_range[0]: return (False, "pH too low") if pH > self.ph_range[1]: return (False, "pH too high") if turbidity > self.turbidity_threshold: return (False, "turbidity too high") - return (True, "Safe") - + # Evaluates each sensor's data and saves the results to a CSV file def evaluate_and_save_results(df, output_path, show_top_n=5): evaluator = WaterQualityEvaluator() @@ -30,7 +29,7 @@ def evaluate_and_save_results(df, output_path, show_top_n=5): safe_count = 0 unsafe_count = 0 - print("\nšŸ”Ž Evaluation Summary:\n") + print("\nEvaluation Summary:\n") # Evaluate all sensor readings for idx, row in df.iterrows(): @@ -69,7 +68,7 @@ def evaluate_and_save_results(df, output_path, show_top_n=5): for entry in results[:show_top_n]: print(f"{entry['sensor']} at {entry['location']}: {entry['status']}") - #Saving only the top N results to CSV (without preview fields) + #Saving only the top N results to CSV export_results = [ { "sensor_id": r["sensor_id"], From f58a044d7dac50907cc8601a41249d51edbe05bc Mon Sep 17 00:00:00 2001 From: Eseroghene Oghojafor Date: Sat, 14 Jun 2025 12:05:28 +0100 Subject: [PATCH 4/5] Finished Water Quality Evaluation Project --- src/__pycache__/clean_data.cpython-312.pyc | Bin 1297 -> 0 bytes src/__pycache__/evaluate.cpython-312.pyc | Bin 3769 -> 0 bytes src/__pycache__/load_data.cpython-312.pyc | Bin 365 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/__pycache__/clean_data.cpython-312.pyc delete mode 100644 src/__pycache__/evaluate.cpython-312.pyc delete mode 100644 src/__pycache__/load_data.cpython-312.pyc diff --git a/src/__pycache__/clean_data.cpython-312.pyc b/src/__pycache__/clean_data.cpython-312.pyc deleted file mode 100644 index d2c6db561a5162025749c97fe568aeeba6aae3ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1297 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 diff --git a/src/__pycache__/load_data.cpython-312.pyc b/src/__pycache__/load_data.cpython-312.pyc deleted file mode 100644 index 222d2572b73f10f84d407f4288cbc6014beb71d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 365 zcmX|5u};G<5WP#P5-1sf9|&UvA|Fu1#7Y;$(j~HDw@H=8!FGX43`npr!Pal6_!JnB z*a9098&bAToTHQ{-Me?b=V!nA{uU744$jhh>fd%)!)ZmmOJV^WIOZ@!?mWQInPcew zSi>N})@PgBR((if0p@=kt!?3kyc5ROUmTTu%mKbdCf#G zD34M*RCJ6fmcRZDRmWva$ WO{4v%_KAL7MEr!kx{J8q*#7{BfKe#` From f2df36a7f07a7a1e8867a04c800712fda1da8785 Mon Sep 17 00:00:00 2001 From: Eseroghene Oghojafor Date: Mon, 16 Jun 2025 13:28:57 +0100 Subject: [PATCH 5/5] feature-water-quality-eavalutor --- src/evaluate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.py b/src/evaluate.py index d64ec175e..36922a9cb 100644 --- a/src/evaluate.py +++ b/src/evaluate.py @@ -79,7 +79,7 @@ def evaluate_and_save_results(df, output_path, show_top_n=5): } for r in results[:show_top_n] ] - +# Creating the output directory and writing the sensor readings to a CSV file os.makedirs(os.path.dirname(output_path), exist_ok=True) with open(output_path, "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=["sensor_id", "location", "ph", "turbidity", "temperature"])