From 147e9424be143156d6451398c13e07825b6805c9 Mon Sep 17 00:00:00 2001 From: Pritimay Sarkar Date: Sun, 3 Dec 2023 23:26:16 +0530 Subject: [PATCH] add device accuracy --- scripts/device_accuracy.py | 159 +++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 scripts/device_accuracy.py diff --git a/scripts/device_accuracy.py b/scripts/device_accuracy.py new file mode 100644 index 0000000..8607c8f --- /dev/null +++ b/scripts/device_accuracy.py @@ -0,0 +1,159 @@ +import pandas as pd +import numpy as np +import os +import re +import xlsxwriter +from datetime import datetime +import math + +curdir = os.getcwd() +path_delim = '/' + +precision_threshold = 0.009 +accuracy_threshold = 0.02 + +denovix_reference_values = { + "Tartrazine": { + "50": 0.187191676, + "75": 0.187191676, + "100": 0.187191676, + "125": 0.187191676, + "150": 0.187191676, + "175": 0.187191676, + "200": 0.187191676, + "225": 0.187191676, + "250": 0.187191676, + "275": 0.187191676, + "300": 0.187191676, + }, + "KMnO4": { + "250": 0.187191676, + "350": 0.187191676, + "450": 0.187191676, + "550": 0.187191676, + "650": 0.187191676, + "750": 0.187191676, + "850": 0.187191676, + "950": 0.187191676, + "1050": 0.187191676, + "1150": 0.187191676, + "1250": 0.187191676, + "1350": 0.187191676, + "1450": 0.187191676, + "1550": 0.187191676, + }, +} +df_reference_device = pd.DataFrame(denovix_reference_values).T +df_reference_device.index.name = 'Solution' +df_reference_device.columns.name = 'Wavelength' + +df = pd.read_excel(curdir + path_delim + "data" + path_delim + "data_03_12_2023_11_25.xlsx", sheet_name="Sheet2") + +texts_to_check = ['Tar', 'KM'] +df['solution'] = df['name'].str.extract(f"({'|'.join(texts_to_check)})", flags=re.IGNORECASE) +df['solution'] = df['solution'].replace({'Tar': 'Tartrazine', 'KM': 'KMnO4'}, regex=True) + +def extract_numbers(s): + match = re.match(r'\d+', s) + if match: + return int(match.group()) + else: + return None + +df["concentration"] = df['name'].apply(extract_numbers) +df['absorbance'] = df.apply(lambda row: row['led2Average'] if row['solution'] == 'Tartrazine' else row['led1Average'], axis=1) + +df_precision_acc = df[["deviceId", "solution", "concentration", "led1Average", "led2Average", "absorbance"]].groupby(["deviceId", "solution", "concentration"]).describe()["absorbance"][["count", "min", "max", "mean"]] +df_precision_acc['precision'] = df_precision_acc['max'] - df_precision_acc['min'] + +df_precision_acc['precision_result'] = ['Fail' if diff > precision_threshold else 'Pass' for diff in df_precision_acc['precision']] + +device_precision_results = {} +for index, group_df in df_precision_acc.groupby(level=[0, 1, 2]): + soln = index[1] + concen = index[2] + result_values = group_df['precision_result'].values + + if index[0] not in device_precision_results: + device_precision_results[index[0]] = "Pass" + else: + result = 'Fail' if 'Fail' in result_values else 'Pass' + if result == 'Fail': + device_precision_results[index[0]] = 'Fail' + +df_device_precicion_results = pd.DataFrame(list(device_precision_results.items()), columns=['Device', 'Result']) + +df_precision_acc = df_precision_acc.assign(accuracy='', accuracy_result='') + +device_accuracy_results = {} + +# Calculate accuracy based on the mean column and reference values +for idx, row in df_precision_acc.iterrows(): + device_id = row.name[0] + solution = row.name[1] + concentration = str(row.name[2]) + reference_value = denovix_reference_values[solution][concentration] + + try: + reference_value = denovix_reference_values[solution][concentration] + accuracy = math.fabs(row['mean'] - reference_value) + df_precision_acc.at[idx, 'accuracy'] = accuracy + + # Add accuracy_result column + accuracy_result = 'Pass' if accuracy < accuracy_threshold else 'Fail' + df_precision_acc.at[idx, 'accuracy_result'] = accuracy_result + if device_id not in device_accuracy_results: + device_accuracy_results[device_id] = accuracy_result + else: + if accuracy_result == 'Fail': + device_accuracy_results[device_id] = 'Fail' + except KeyError: + # Handle the case where the solution or concentration is not in the dictionary + df_precision_acc.at[idx, 'accuracy'] = np.nan # You can use any value to represent missing data + df_precision_acc.at[idx, 'accuracy_result'] = 'Fail' # Assume 'Fail' for missing data + +df_device_accuracy_results = pd.DataFrame(list(device_accuracy_results.items()), columns=['Device', 'Result']) + +device_results = {} + +# Mark deviceId as "Fail" if either precision or accuracy is failing +df_device_results = pd.merge(df_device_precicion_results, df_device_accuracy_results, on='Device', how='outer', suffixes=('_precision', '_accuracy')) +df_device_results['Result'] = np.where((df_device_results['Result_precision'] == 'Fail') | (df_device_results['Result_accuracy'] == 'Fail'), 'Fail', 'Pass') + + +output_filename = f'precision_{datetime.today().strftime("%d_%m_%Y_%H_%M")}.xlsx' +writer = pd.ExcelWriter(output_filename, engine = 'xlsxwriter') +df_device_results.to_excel(writer, sheet_name="device_results") +df_device_precicion_results.to_excel(writer, sheet_name="device_precision") +df_device_accuracy_results.to_excel(writer, sheet_name="device_accuracy") +df_precision_acc.to_excel(writer, sheet_name="concentration") +df.to_excel(writer, sheet_name="in") +df_reference_device.to_excel(writer, sheet_name="reference_device") + +workbook = writer.book +worksheet_device_results = writer.sheets['device_results'] + +red_format = workbook.add_format({'bg_color': '#FFC7CE', 'font_color': '#9C0006'}) +green_format = workbook.add_format({'bg_color': '#C6EFCE', 'font_color': '#006100'}) + +worksheet_device_results.conditional_format('E2:E{}'.format(df_device_results.shape[0] + 1), {'type': 'text', + 'criteria': 'containing', + 'value': 'Fail', + 'format': red_format}) + +worksheet_device_results.conditional_format('E2:E{}'.format(df_device_results.shape[0] + 1), {'type': 'text', + 'criteria': 'containing', + 'value': 'Pass', + 'format': green_format}) + +### debug each row +# # Merge df and df_device_precicion_results on deviceId +# df_merged = pd.merge(df, df_device_precicion_results, left_on='deviceId', right_on='Device', how='left') + +# # Drop the duplicate "Device" column +# df_merged.drop(columns=['Device'], inplace=True) + +# # Save the merged DataFrame to the Excel file +# df_merged.to_excel(writer, sheet_name="merged_results") + +writer.close() \ No newline at end of file