import gradio as gr import xgboost as xgb import joblib import numpy as np from sklearn.preprocessing import StandardScaler import pandas as pd import shap import matplotlib.pyplot as plt # Load the model and the scaler model = joblib.load('best_XGB.pkl') scaler = joblib.load('scaler.pkl') # Ensure the scaler is saved and loaded with the same scikit-learn version cutoff = 42 # Custom cutoff probability # Use TreeExplainer for XGBoost models explainer = shap.TreeExplainer(model) # Define the function to draw the semicircular scale def draw_scale(probability): fig, ax = plt.subplots(figsize=(6, 3)) # Plot the semicircular scale ax.barh(0, 1, color='green', left=0, height=0.3) ax.barh(0, 1, color='red', left=cutoff / 100, height=0.3) # Add arrow indicator based on predicted probability arrow_position = probability / 100 color = 'green' if probability < cutoff else 'red' ax.annotate('', xy=(arrow_position, 0.15), xytext=(arrow_position, 0.3), arrowprops=dict(facecolor=color, shrink=0.05)) # Remove axes and add labels ax.set_xlim(0, 1) ax.set_ylim(-0.5, 0.5) ax.axis('off') # Save the image plt.savefig('scale_plot.png', bbox_inches='tight') plt.close() # Define the prediction function with preprocessing, scaling, and SHAP analysis def predict_heart_attack(Gender, age, cigsPerDay, BPMeds, prevalentHyp, diabetes, totChol, sysBP, diaBP, BMI, heartRate, glucose): # Define feature names in the same order as the training data feature_names = ['Gender', 'age', 'cigsPerDay', 'BPMeds', 'prevalentHyp', 'diabetes', 'totChol', 'sysBP', 'diaBP', 'BMI', 'heartRate', 'glucose'] # Create a DataFrame with the correct feature names for prediction features = pd.DataFrame([[Gender, age, cigsPerDay, BPMeds, prevalentHyp, diabetes, totChol, sysBP, diaBP, BMI, heartRate, glucose]], columns=feature_names) # Standardize the features (scaling) scaled_features = scaler.transform(features) # Predict probabilities proba = model.predict_proba(scaled_features)[:, 1] # Probability of class 1 (heart attack) # Apply custom cutoff if proba[0] * 100 >= cutoff: prediction_class = "Heart_Attack_Risk.Consult your doctor" else: prediction_class = "No_Heart_Attack_Risk.Still make regular checkup" # Generate SHAP values for the prediction using the explainer shap_values = explainer(features) # Plot SHAP values plt.figure(figsize=(8, 6)) shap.waterfall_plot(shap_values[0]) # Using the SHAP Explanation object plt.savefig('shap_plot.png') # Save SHAP plot to a file # Draw semicircular scale draw_scale(proba[0] * 100) result = f"Predicted Probability: {proba[0] * 100:.2f}%. Predicted Class with cutoff {cutoff}%: {prediction_class}" return result, 'scale_plot.png', 'shap_plot.png' # Return the prediction, scale, and SHAP plot # Create the Gradio interface with preprocessing, prediction, and SHAP visualization with gr.Blocks() as app: with gr.Row(): with gr.Column(): Gender = gr.Radio([0, 1], label="Gender (0=Female, 1=Male)") cigsPerDay = gr.Slider(0, 40, step=1, label="Cigarettes per Day") prevalentHyp = gr.Radio([0, 1], label="Prevalent Hypertension (0=No, 1=Yes)") totChol = gr.Slider(100, 400, step=1, label="Total Cholesterol in mg/dl") diaBP = gr.Slider(60, 120, step=1, label="Diastolic/Lower BP") heartRate = gr.Slider(50, 120, step=1, label="Heart Rate") with gr.Column(): age = gr.Slider(20, 80, step=1, label="Age (years)") BPMeds = gr.Radio([0, 1], label="On BP Medications (0=No, 1=Yes)") diabetes = gr.Radio([0, 1], label="Diabetes (0=No, 1=Yes)") sysBP = gr.Slider(90, 200, step=1, label="Systolic BP/Higher BP") BMI = gr.Slider(15, 40, step=0.1, label="Body Mass Index (BMI) in kg/m2") glucose = gr.Slider(50, 250, step=1, label="Fasting Glucose Level") # Display disclaimer in red uppercase letters above the scale gr.HTML("