ThyroidCancer / app.py
WillHbx's picture
Added probabilities to prediction
e6a74b4
Raw
History Blame Contribute Delete
7.33 kB
import gradio as gr
import pickle
import subprocess
import sys
inputs_fields = ['Age',
'Gender',
'Smoking',
'Hx Smoking',
'Hx Radiothreapy',
'Thyroid Function',
'Physical Examination',
'Adenopathy',
'Pathology',
'Focality',
'Risk',
'T',
'N',
'M',
'Stage',
'Response'
]
inputs_for_categorical_fields_values = {
'Gender' : ['F', 'M'],
'Smoking': ['No', 'Yes'],
'Hx Smoking (Smoking History)' :['No', 'Yes'],
'Hx Radiothreapy (Radiotherapy History)':['No', 'Yes'],
'Thyroid Function':['Euthyroid', 'Clinical Hyperthyroidism', 'Clinical Hypothyroidism'
, 'Subclinical Hyperthyroidism', 'Subclinical Hypothyroidism'],
'Physical Examination':['Single nodular goiter-left', 'Multinodular goiter'
, 'Single nodular goiter-right', 'Normal', 'Diffuse goiter'],
'Adenopathy': ['No', 'Right', 'Extensive', 'Left', 'Bilateral', 'Posterior'],
'Pathology':['Micropapillary', 'Papillary', 'Follicular', 'Hurthel cell'],
'Focality':['Uni-Focal', 'Multi-Focal'],
'Risk':['Low', 'Intermediate', 'High'],
'Tumor':['T1a (tumor that is 1 cm or smaller)', 'T1b (tumor between 1cm and 2cm)', 'T2 (tumor between 2cm and 4cm)',
'T3a (tumor larger than 4 cm)', 'T3b (tumor that has grown outside the thyroid)',
'T4a (tumor that has invaded nearby structures)', 'T4b (tumor that has invaded nearby structures)'],
'Lymph Nodes':['N0 (no evidence of regional lymph node metastasis)',
'N1b (regional lymph node metastasis in the central of the neck)',
'N1a (regional lymph node metastasis in the lateral of the neck)'],
'Cancer Metastasis':['M0 (no evidence of distant metastasis)', 'M1 (the presence of distant metastasis)'],
'Stage':['I', 'II', 'IVB', 'III', 'IVA'],
'Response':['Indeterminate', 'Excellent', 'Structural Incomplete', 'Biochemical Incomplete']
}
expected_inputs = ['Age',
'Gender_F',
'Gender_M',
'Smoking_No',
'Smoking_Yes',
'Hx Smoking_No',
'Hx Smoking_Yes',
'Hx Radiothreapy_No',
'Hx Radiothreapy_Yes',
'Thyroid Function_Clinical Hyperthyroidism',
'Thyroid Function_Clinical Hypothyroidism',
'Thyroid Function_Euthyroid',
'Thyroid Function_Subclinical Hyperthyroidism',
'Thyroid Function_Subclinical Hypothyroidism',
'Physical Examination_Diffuse goiter',
'Physical Examination_Multinodular goiter',
'Physical Examination_Normal',
'Physical Examination_Single nodular goiter-left',
'Physical Examination_Single nodular goiter-right',
'Adenopathy_Bilateral',
'Adenopathy_Extensive',
'Adenopathy_Left',
'Adenopathy_No',
'Adenopathy_Posterior',
'Adenopathy_Right',
'Pathology_Follicular',
'Pathology_Hurthel cell',
'Pathology_Micropapillary',
'Pathology_Papillary',
'Focality_Multi-Focal',
'Focality_Uni-Focal',
'Risk_High',
'Risk_Intermediate',
'Risk_Low',
'T_T1a',
'T_T1b',
'T_T2',
'T_T3a',
'T_T3b',
'T_T4a',
'T_T4b',
'N_N0',
'N_N1a',
'N_N1b',
'M_M0',
'M_M1',
'Stage_I',
'Stage_II',
'Stage_III',
'Stage_IVA',
'Stage_IVB',
'Response_Biochemical Incomplete',
'Response_Excellent',
'Response_Indeterminate',
'Response_Structural Incomplete']
def normalize_age(user_age, age_min=15, age_max=82):
user_age = int(user_age)
assert age_min <= user_age <= age_max, f"Age must be between {age_min} and {age_max}"
assert user_age >= 0, "Age must be a positive integer"
# Normalize age using the min and max from training
normalized_age = (user_age - age_min) / (age_max - age_min)
return int(normalized_age)
def transform_input_to_expected_format(user_input):
# Initialize output dictionary with all expected inputs set to 0
transformed_input = {feature: 0 for feature in expected_inputs}
for field, value in user_input.items():
if type(value) == str:
value = value.split(' (')[0]
if field == 'Tumor':
field = 'T'
if field == 'Lymph Nodes':
field = 'N'
if field == 'Cancer Metastasis':
field = 'M'
if field == 'Age':
transformed_input['Age'] = normalize_age(value)
else:
key = f"{field}_{value}"
if key in transformed_input:
transformed_input[key] = 1
return transformed_input
def predict_thyroid_cancer(Age, Gender, Smoking, Hx_Smoking, Hx_Radiothreapy,Thyroid_Function, Physical_Examination, Adenopathy, Pathology, Focality, Risk, T, N, M, Stage, Response):
inputs = {
'Age': int(Age),
'Gender': Gender,
'Smoking': Smoking,
'Hx Smoking': Hx_Smoking,
'Hx Radiothreapy': Hx_Radiothreapy,
'Thyroid Function': Thyroid_Function,
'Physical Examination': Physical_Examination,
'Adenopathy': Adenopathy,
'Pathology': Pathology,
'Focality': Focality,
'Risk': Risk,
'T': T,
'N': N,
'M': M,
'Stage': Stage,
'Response': Response
}
with open('random_forest_model.pkl', 'rb') as model_file:
model = pickle.load(model_file)
transformed_input = list(transform_input_to_expected_format(inputs).values())
# Prediction
predictions = model.predict([transformed_input])
risk_level = 'high' if predictions[0] == 1 else 'low'
# Probabilities
probabilities = model.predict_proba([transformed_input])[0]
class_probabilities = dict(zip(model.classes_, probabilities))
probabilities_str = ", ".join([f"{'low risk' if cls == 0.0 else 'high risk'} at {prob * 100:.2f}%" for cls, prob in class_probabilities.items()])
return f"Patient has {risk_level} risk of thyroid cancer recurrence.\nProbabilities: {probabilities_str}"
# Intall required packages
packages = ["scikit-learn"]
subprocess.check_call([sys.executable, "-m", "pip", "install"] + packages)
dropdown_inputs = [
gr.Textbox(label="Age (between 15 and 82)")
]
for field, choices in inputs_for_categorical_fields_values.items():
dropdown_inputs.append(gr.Dropdown(choices=choices, label=field))
demo = gr.Interface(fn=predict_thyroid_cancer, inputs=dropdown_inputs, outputs="text")
demo.launch(share=True)