| |
|
|
| import gradio as gr |
| import pandas as pd |
| import numpy as np |
| import joblib |
| import matplotlib.pyplot as plt |
| import os |
| import sys |
| from lime import lime_tabular |
|
|
| |
| print("Python version:", sys.version) |
| print("Current working directory:", os.getcwd()) |
| print("Files in current directory:", os.listdir()) |
|
|
| |
| lime_explainer = None |
|
|
| |
| try: |
| print("Model loading attempt...") |
| model = joblib.load('optimized_random_forest_model.pkl') |
| print("Model loaded successfully!") |
| |
| print("Preprocessor loading attempt...") |
| preprocessor = joblib.load('preprocessor.pkl') |
| print("Preprocessor loaded successfully!") |
| |
| |
| categorical_features = ['gender', 'oral', 'tartar'] |
| numerical_features = ['age', 'height(cm)', 'weight(kg)', 'waist(cm)', 'eyesight(left)', |
| 'eyesight(right)', 'hearing(left)', 'hearing(right)', 'systolic', |
| 'relaxation', 'fasting blood sugar', 'Cholesterol', 'triglyceride', |
| 'HDL', 'LDL', 'hemoglobin', 'Urine protein', 'serum creatinine', |
| 'AST', 'ALT', 'Gtp', 'dental caries'] |
|
|
| |
| try: |
| print("Preparing feature names...") |
| numeric_feature_names = numerical_features.copy() |
| categorical_encoder = preprocessor.named_transformers_['cat'] |
| onehot_encoder = categorical_encoder.named_steps['onehot'] |
| encoded_feature_names = onehot_encoder.get_feature_names_out(categorical_features) |
| all_feature_names = np.concatenate([numeric_feature_names, encoded_feature_names]) |
| print("Feature names prepared successfully!") |
| |
| |
| print("Checking categorical variable categories...") |
| categories = onehot_encoder.categories_ |
| for i, cat in enumerate(categorical_features): |
| print(f"{cat} categories: {categories[i]}") |
| |
| |
| print("LIME explainer will be initialized during first prediction") |
| |
| except Exception as e: |
| print(f"Error preparing feature names: {e}") |
| all_feature_names = numerical_features + [f"{cat}_{val}" for cat in categorical_features for val in ['M', 'F', 'Y', 'N']] |
| print("Using default feature names:", all_feature_names[:5], "...") |
|
|
| except Exception as e: |
| print(f"Critical error loading model or preprocessor: {e}") |
| print("Model files may be missing or corrupted.") |
| error_message = f"Error loading model: {str(e)}" |
|
|
| def get_instance_feature_importance_lime(processed_data, input_data): |
| """ |
| LIME is used to calculate the feature importance values for a prediction |
| """ |
| global lime_explainer |
| |
| try: |
| |
| if lime_explainer is None: |
| print("Initializing LIME explainer for the first time...") |
| |
| lime_explainer = lime_tabular.LimeTabularExplainer( |
| training_data=processed_data, |
| feature_names=all_feature_names, |
| class_names=["Non-Smoker", "Smoker"], |
| mode="classification", |
| discretize_continuous=True |
| ) |
| print("LIME explainer initialized") |
|
|
| |
| print("Generating LIME explanation...") |
| explanation = lime_explainer.explain_instance( |
| data_row=processed_data[0], |
| predict_fn=model.predict_proba, |
| num_features=5, |
| top_labels=1 |
| ) |
| |
| |
| most_likely_class_idx = explanation.top_labels[0] |
| |
| |
| feature_importance = explanation.as_list(label=most_likely_class_idx) |
| top_features = [feature_name for feature_name, importance in feature_importance] |
| |
| print(f"LIME explanation generated: {top_features}") |
| return top_features |
| |
| except Exception as e: |
| print(f"Error calculating LIME feature importance: {e}") |
| import traceback |
| traceback.print_exc() |
| |
| |
| print("Falling back to global feature importances...") |
| try: |
| feature_importances = model.feature_importances_ |
| feature_importance_df = pd.DataFrame({ |
| 'Feature': all_feature_names, |
| 'Importance': feature_importances |
| }).sort_values('Importance', ascending=False) |
| |
| return feature_importance_df.head(5)['Feature'].tolist() |
| except: |
| return ["Feature importance calculation failed"] |
|
|
| def make_prediction(age, gender, height, weight, waist, eyesight_left, eyesight_right, |
| hearing_left, hearing_right, systolic, relaxation, fasting_blood_sugar, |
| cholesterol, triglyceride, hdl, ldl, hemoglobin, urine_protein, |
| serum_creatinine, ast, alt, gtp, tartar, dental_caries): |
| |
| try: |
| print("Prediction function called") |
| |
| |
| oral = 'Y' |
| |
| |
| try: |
| categorical_encoder = preprocessor.named_transformers_['cat'] |
| onehot_encoder = categorical_encoder.named_steps['onehot'] |
| categories = onehot_encoder.categories_ |
| |
| |
| gender_values = categories[0] |
| tartar_values = categories[2] |
| |
| print(f"Valid gender values for the model: {gender_values}") |
| print(f"Valid tartar values for the model: {tartar_values}") |
| |
| |
| if gender not in gender_values: |
| print(f"WARNING: '{gender}' is not a valid 'gender' value. Using '{gender_values[0]}'.") |
| gender = gender_values[0] |
| |
| if tartar not in tartar_values: |
| print(f"WARNING: '{tartar}' is not a valid 'tartar' value. Using '{tartar_values[0]}'.") |
| tartar = tartar_values[0] |
| except Exception as e: |
| print(f"Error during categorical variable validation: {e}") |
| |
| |
| input_data = pd.DataFrame({ |
| 'age': [age], |
| 'gender': [gender], |
| 'height(cm)': [height], |
| 'weight(kg)': [weight], |
| 'waist(cm)': [waist], |
| 'eyesight(left)': [eyesight_left], |
| 'eyesight(right)': [eyesight_right], |
| 'hearing(left)': [hearing_left], |
| 'hearing(right)': [hearing_right], |
| 'systolic': [systolic], |
| 'relaxation': [relaxation], |
| 'fasting blood sugar': [fasting_blood_sugar], |
| 'Cholesterol': [cholesterol], |
| 'triglyceride': [triglyceride], |
| 'HDL': [hdl], |
| 'LDL': [ldl], |
| 'hemoglobin': [hemoglobin], |
| 'Urine protein': [urine_protein], |
| 'serum creatinine': [serum_creatinine], |
| 'AST': [ast], |
| 'ALT': [alt], |
| 'Gtp': [gtp], |
| 'oral': [oral], |
| 'tartar': [tartar], |
| 'dental caries': [dental_caries] |
| }) |
| |
| print("Preprocessing data...") |
| |
| processed_data = preprocessor.transform(input_data) |
| print("Preprocessing completed!") |
| |
| print("Making prediction...") |
| |
| prediction_proba = model.predict_proba(processed_data)[0] |
| prediction = model.predict(processed_data)[0] |
| print(f"Prediction result: {prediction}, Probability: {prediction_proba}") |
| |
| |
| if prediction == 1: |
| result = "Smoker" |
| probability = prediction_proba[1] * 100 |
| else: |
| result = "Non-Smoker" |
| probability = prediction_proba[0] * 100 |
| |
| |
| print("Calculating instance-specific feature importance with LIME...") |
| top_features = get_instance_feature_importance_lime(processed_data, input_data) |
| top_features_str = ", ".join(top_features) |
| print(f"Top features for this instance: {top_features_str}") |
| |
| print("Prediction completed, results returned") |
| return result, f"{probability:.2f}%", top_features_str |
| |
| except Exception as e: |
| print(f"Unexpected error during prediction: {e}") |
| return f"Error: {str(e)}", "Error occurred", "Prediction failed" |
|
|
| |
| print("Creating Gradio interface...") |
| with gr.Blocks(title="Smoking Status Prediction") as app: |
| gr.Markdown("# Smoking Status Prediction Model") |
| gr.Markdown("""This application predicts whether a person is a smoker based on health and demographic data. |
| The model uses Random Forest classifier trained on a dataset of health indicators.""") |
| |
| with gr.Tab("Make Prediction"): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| gr.Markdown("### Demographics") |
| age = gr.Slider(18, 90, step=1, label="Age", value=40) |
| gender = gr.Dropdown(["M", "F"], label="Gender", value="M") |
| height = gr.Slider(140, 200, step=1, label="Height (cm)", value=170) |
| weight = gr.Slider(40, 150, step=1, label="Weight (kg)", value=70) |
| waist = gr.Slider(50, 150, step=1, label="Waist Circumference (cm)", value=85) |
| |
| gr.Markdown("### Vision and Hearing") |
| eyesight_left = gr.Slider(0.1, 2.0, step=0.1, label="Eyesight (Left)", value=1.0) |
| eyesight_right = gr.Slider(0.1, 2.0, step=0.1, label="Eyesight (Right)", value=1.0) |
| hearing_left = gr.Slider(0.0, 1.0, step=0.1, label="Hearing (Left)", value=1.0) |
| hearing_right = gr.Slider(0.0, 1.0, step=0.1, label="Hearing (Right)", value=1.0) |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### Blood Pressure and Sugar") |
| systolic = gr.Slider(90, 200, step=1, label="Systolic Blood Pressure", value=120) |
| relaxation = gr.Slider(50, 150, step=1, label="Diastolic Blood Pressure", value=80) |
| fasting_blood_sugar = gr.Slider(50, 300, step=1, label="Fasting Blood Sugar", value=95) |
| |
| gr.Markdown("### Cholesterol Profile") |
| cholesterol = gr.Slider(100, 350, step=1, label="Total Cholesterol", value=190) |
| triglyceride = gr.Slider(30, 600, step=1, label="Triglyceride", value=120) |
| hdl = gr.Slider(20, 100, step=1, label="HDL Cholesterol", value=55) |
| ldl = gr.Slider(30, 250, step=1, label="LDL Cholesterol", value=110) |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### Blood and Urine Tests") |
| hemoglobin = gr.Slider(8, 20, step=0.1, label="Hemoglobin", value=14.0) |
| urine_protein = gr.Slider(1, 6, step=1, label="Urine Protein", value=1) |
| serum_creatinine = gr.Slider(0.2, 2.0, step=0.1, label="Serum Creatinine", value=0.9) |
| |
| gr.Markdown("### Liver Function") |
| ast = gr.Slider(10, 200, step=1, label="AST", value=25) |
| alt = gr.Slider(10, 200, step=1, label="ALT", value=25) |
| gtp = gr.Slider(10, 300, step=1, label="GTP", value=30) |
| |
| gr.Markdown("### Dental Health") |
| |
| tartar = gr.Dropdown(["Y", "N"], label="Tartar", value="Y") |
| dental_caries = gr.Slider(0, 3, step=1, label="Dental Caries", value=0) |
| |
| predict_btn = gr.Button("Predict Smoking Status") |
| |
| with gr.Row(): |
| with gr.Column(): |
| prediction_result = gr.Textbox(label="Prediction Result") |
| probability_result = gr.Textbox(label="Confidence") |
| top_features = gr.Textbox(label="Top Features for This Prediction") |
| |
| with gr.Tab("Model Information"): |
| gr.Markdown("## Model Information") |
| gr.Markdown(""" |
| ### Random Forest Classifier |
| |
| This model uses a Random Forest Classifier to predict smoking status based on health indicators. |
| |
| The model was trained on a dataset containing demographic, biometric, and health-related features. |
| |
| ### Top Features Used by the Model |
| |
| The most important features for prediction include: |
| - Hemoglobin |
| - HDL Cholesterol (higher in non-smokers) |
| - Age |
| - Gender |
| - Height |
| - Weight |
| |
| ### Model Performance |
| |
| On the test dataset, the model achieved: |
| - Accuracy: ~80% |
| - Precision: ~78% |
| - Recall: ~79% |
| """) |
| |
| |
| predict_btn.click( |
| fn=make_prediction, |
| inputs=[age, gender, height, weight, waist, eyesight_left, eyesight_right, |
| hearing_left, hearing_right, systolic, relaxation, fasting_blood_sugar, |
| cholesterol, triglyceride, hdl, ldl, hemoglobin, urine_protein, |
| serum_creatinine, ast, alt, gtp, tartar, dental_caries], |
| outputs=[prediction_result, probability_result, top_features] |
| ) |
|
|
| print("Gradio interface created, launching application...") |
| |
| if __name__ == "__main__": |
| app.launch() |