|
import gradio as gr |
|
import xgboost as xgb |
|
import pandas as pd |
|
import numpy as np |
|
from sklearn.model_selection import train_test_split |
|
from sklearn.metrics import accuracy_score, confusion_matrix |
|
import plotly.express as px |
|
import plotly.graph_objects as go |
|
import json |
|
|
|
class DiabetesGame: |
|
def __init__(self): |
|
self.data = self.load_data() |
|
self.model = self.train_model() |
|
self.user_score = 0 |
|
self.total_attempts = 0 |
|
self.tips_database = { |
|
"glucose": "Normal fasting blood glucose levels are less than 100 mg/dL. Levels between 100-125 mg/dL indicate prediabetes.", |
|
"bmi": "A BMI between 18.5 and 24.9 is considered healthy. BMI over 30 indicates obesity, a risk factor for diabetes.", |
|
"blood_pressure": "Normal blood pressure is usually below 120/80 mmHg. High blood pressure often co-occurs with diabetes.", |
|
"age": "Type 2 diabetes risk increases with age, particularly after 45 years.", |
|
"pregnancies": "Gestational diabetes during pregnancy increases future diabetes risk.", |
|
"lifestyle": "Regular exercise and a balanced diet can significantly reduce diabetes risk.", |
|
"family_history": "Having a parent or sibling with diabetes increases your risk.", |
|
"general": "Early detection and lifestyle changes can prevent or delay type 2 diabetes." |
|
} |
|
|
|
def load_data(self): |
|
return pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/diabetes.csv') |
|
|
|
def train_model(self): |
|
X = self.data.drop(columns=['Outcome']) |
|
y = self.data['Outcome'] |
|
X_train, _, y_train, _ = train_test_split(X, y, test_size=0.2, random_state=42) |
|
|
|
model = xgb.XGBClassifier( |
|
eval_metric='logloss', |
|
max_depth=6, |
|
learning_rate=0.1, |
|
n_estimators=100, |
|
random_state=42 |
|
) |
|
model.fit(X_train, y_train) |
|
return model |
|
|
|
def create_radar_chart(self, values): |
|
categories = ['Pregnancies', 'Glucose', 'Blood Pressure', 'Skin Thickness', |
|
'Insulin', 'BMI', 'Diabetes Pedigree', 'Age'] |
|
|
|
|
|
max_values = [17, 200, 122, 99, 846, 67.1, 2.42, 81] |
|
normalized_values = [v/m for v, m in zip(values, max_values)] |
|
|
|
fig = go.Figure() |
|
fig.add_trace(go.Scatterpolar( |
|
r=normalized_values, |
|
theta=categories, |
|
fill='toself', |
|
name='Patient Values' |
|
)) |
|
|
|
fig.update_layout( |
|
polar=dict( |
|
radialaxis=dict( |
|
visible=True, |
|
range=[0, 1] |
|
)), |
|
showlegend=True, |
|
title="Patient Risk Factors Radar Chart" |
|
) |
|
return fig |
|
|
|
def create_feature_importance_plot(self): |
|
importance_df = pd.DataFrame({ |
|
'Feature': ['Pregnancies', 'Glucose', 'Blood Pressure', 'Skin Thickness', |
|
'Insulin', 'BMI', 'Diabetes Pedigree', 'Age'], |
|
'Importance': self.model.feature_importances_ |
|
}) |
|
importance_df = importance_df.sort_values('Importance', ascending=True) |
|
|
|
fig = px.bar(importance_df, x='Importance', y='Feature', |
|
orientation='h', |
|
title='Feature Importance in Diagnosis') |
|
fig.update_layout(height=400) |
|
return fig |
|
|
|
def get_relevant_tips(self, values): |
|
tips = [] |
|
|
|
|
|
if values[1] > 140: |
|
tips.append(("β οΈ High Glucose", self.tips_database["glucose"])) |
|
if values[5] > 30: |
|
tips.append(("β οΈ High BMI", self.tips_database["bmi"])) |
|
if values[2] > 90: |
|
tips.append(("β οΈ High Blood Pressure", self.tips_database["blood_pressure"])) |
|
|
|
|
|
general_tips = [self.tips_database["lifestyle"], |
|
self.tips_database["family_history"], |
|
self.tips_database["general"]] |
|
tips.append(("π‘ Health Tip", np.random.choice(general_tips))) |
|
|
|
return "\n\n".join([f"{title}\n{content}" for title, content in tips]) |
|
|
|
def predict_and_play(self, pregnancies, glucose, blood_pressure, skin_thickness, |
|
insulin, bmi, diabetes_pedigree, age, user_diagnosis): |
|
|
|
values = [pregnancies, glucose, blood_pressure, skin_thickness, |
|
insulin, bmi, diabetes_pedigree, age] |
|
|
|
|
|
user_input = np.array(values).reshape(1, -1) |
|
prediction = self.model.predict(user_input)[0] |
|
probability = self.model.predict_proba(user_input)[0][1] * 100 |
|
|
|
|
|
self.total_attempts += 1 |
|
correct = (user_diagnosis == "Yes" and prediction == 1) or \ |
|
(user_diagnosis == "No" and prediction == 0) |
|
if correct: |
|
self.user_score += 1 |
|
|
|
|
|
radar_chart = self.create_radar_chart(values) |
|
importance_plot = self.create_feature_importance_plot() |
|
|
|
|
|
accuracy = (self.user_score / self.total_attempts) * 100 if self.total_attempts > 0 else 0 |
|
|
|
result = f"""{'π Correct!' if correct else 'β Incorrect'}\n |
|
Model Prediction: {'Diabetes Risk Detected' if prediction == 1 else 'No Significant Risk'}\n |
|
Confidence: {probability:.1f}%\n |
|
Your Score: {self.user_score}/{self.total_attempts} ({accuracy:.1f}% accuracy) |
|
""" |
|
|
|
|
|
tips = self.get_relevant_tips(values) |
|
|
|
return result, radar_chart, importance_plot, tips |
|
|
|
|
|
game = DiabetesGame() |
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft()) as interface: |
|
gr.Markdown(""" |
|
# π₯ Interactive Diabetes Diagnosis Game |
|
|
|
Test your medical diagnosis skills! Analyze patient data and try to predict diabetes risk. |
|
Your score will be tracked as you play. |
|
|
|
## How to Play: |
|
1. Adjust the patient parameters using the sliders |
|
2. Make your diagnosis (Yes/No for diabetes risk) |
|
3. Submit to see if you matched the model's prediction |
|
4. Learn from the visualizations and tips |
|
""") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
pregnancies = gr.Slider(0, 17, step=1, label="Pregnancies") |
|
glucose = gr.Slider(0, 200, value=120, step=1, label="Glucose Level") |
|
blood_pressure = gr.Slider(0, 122, value=70, step=1, label="Blood Pressure") |
|
skin_thickness = gr.Slider(0, 99, value=20, step=1, label="Skin Thickness") |
|
|
|
with gr.Column(): |
|
insulin = gr.Slider(0, 846, value=80, step=1, label="Insulin") |
|
bmi = gr.Slider(0.0, 67.1, value=25.0, step=0.1, label="BMI") |
|
diabetes_pedigree = gr.Slider(0.078, 2.42, value=0.5, step=0.001, label="Diabetes Pedigree") |
|
age = gr.Slider(21, 81, value=30, step=1, label="Age") |
|
|
|
diagnosis = gr.Radio(["Yes", "No"], label="Your Diagnosis", info="Do you think this patient has diabetes?") |
|
submit_btn = gr.Button("Submit Diagnosis", variant="primary") |
|
|
|
with gr.Row(): |
|
result_box = gr.Textbox(label="Game Result", lines=5) |
|
tips_box = gr.Textbox(label="Health Tips & Information", lines=5) |
|
|
|
with gr.Row(): |
|
radar_plot = gr.Plot(label="Patient Risk Factors") |
|
importance_plot = gr.Plot(label="Feature Importance") |
|
|
|
submit_btn.click( |
|
fn=game.predict_and_play, |
|
inputs=[pregnancies, glucose, blood_pressure, skin_thickness, |
|
insulin, bmi, diabetes_pedigree, age, diagnosis], |
|
outputs=[result_box, radar_plot, importance_plot, tips_box] |
|
) |
|
|
|
gr.Markdown(""" |
|
## π About the Features |
|
|
|
- **Pregnancies**: Number of times pregnant |
|
- **Glucose**: Plasma glucose concentration (2 hours in an oral glucose tolerance test) |
|
- **Blood Pressure**: Diastolic blood pressure (mm Hg) |
|
- **Skin Thickness**: Triceps skin fold thickness (mm) |
|
- **Insulin**: 2-Hour serum insulin (mu U/ml) |
|
- **BMI**: Body mass index (weight in kg/(height in m)Β²) |
|
- **Diabetes Pedigree**: A function scoring likelihood of diabetes based on family history |
|
- **Age**: Age in years |
|
""") |
|
|
|
if __name__ == "__main__": |
|
interface.launch() |