PCOS-ML / app.py
Zane Vijay Falcao
Upload folder using huggingface_hub
d3915f5 verified
import gradio as gr
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pickle
import joblib
import os
# Load the trained model (try both joblib and pickle in case one fails)
def load_model():
try:
model = joblib.load('pcos_model.joblib')
print("Model loaded using joblib")
return model
except:
try:
with open('random_forest_model', 'rb') as file:
model = pickle.load(file)
print("Model loaded using pickle from random_forest_model")
return model
except:
try:
with open('random_forest_model.pkl', 'rb') as file:
model = pickle.load(file)
print("Model loaded using pickle from pcos_model.pkl")
return model
except Exception as e:
print(f"Error loading model: {e}")
# Fallback to a simple model for demo purposes
from sklearn.ensemble import RandomForestClassifier
print("Creating a fallback model for demonstration")
fallback_model = RandomForestClassifier(n_estimators=100, random_state=42)
# Train with dummy data to initialize
X_dummy = np.random.rand(100, 43)
y_dummy = np.random.choice([0, 1], 100)
fallback_model.fit(X_dummy, y_dummy)
return fallback_model
# Load the model
model = load_model()
# Define the features required for prediction
features = [
"Age (yrs)", "Weight (Kg)", "Height(Cm)", "BMI", "Blood Group", "Pulse rate(bpm)",
"RR (breaths/min)", "Hb(g/dl)", "Cycle length(days)", "Cycle(R/I)", "Marraige Status (Yrs)",
"Pregnant(Y/N)", "No. of abortions", "Hip(inch)", "Waist(inch)", "Waist:Hip Ratio",
"Weight gain(Y/N)", "hair growth(Y/N)", "Skin darkening (Y/N)", "Hair loss(Y/N)",
"Pimples(Y/N)", "Fast food (Y/N)", "Reg.Exercise(Y/N)", "BP _Systolic (mmHg)",
"BP _Diastolic (mmHg)", "Follicle No. (L)", "Follicle No. (R)", "Avg. F size (L) (mm)",
"Avg. F size (R) (mm)", "Endometrium (mm)", "FSH(mIU/mL)", "LH(mIU/mL)", "FSH/LH",
"Hip:Waist Ratio", "TSH (mIU/L)", "AMH(ng/mL)", "PRL(ng/mL)", "Vit D3 (ng/mL)",
"PRG(ng/mL)", "RBS(mg/dl)", "Weight gain", "I beta-HCG(mIU/mL)", "II beta-HCG(mIU/mL)"
]
# Create visualizations for the dashboard
def create_visualizations():
# For demo purposes, we'll use sample data similar to what was in your notebook
# In a real application, you would load the actual dataset
# Sample data for visualization (small dataset for demo)
np.random.seed(42)
n_samples = 100
# Create sample data
sample_data = {
"Age (yrs)": np.random.normal(25, 5, n_samples),
"PCOS (Y/N)": np.random.choice([0, 1], n_samples, p=[0.6, 0.4]),
"BMI": np.random.normal(25, 5, n_samples),
"Cycle length(days)": np.random.normal(28, 5, n_samples),
"Follicle No. (L)": np.random.normal(12, 5, n_samples),
"Follicle No. (R)": np.random.normal(12, 5, n_samples),
"Endometrium (mm)": np.random.normal(8, 2, n_samples),
"Cycle(R/I)": np.random.choice([2, 4], n_samples),
"Weight (Kg)": np.random.normal(65, 10, n_samples),
"Hb(g/dl)": np.random.normal(12, 1.5, n_samples)
}
# Create a DataFrame
df = pd.DataFrame(sample_data)
# For PCOS cases, adjust the values to show differences
pcos_indices = df["PCOS (Y/N)"] == 1
df.loc[pcos_indices, "BMI"] += 2
df.loc[pcos_indices, "Cycle length(days)"] += 5
df.loc[pcos_indices, "Follicle No. (L)"] += 8
df.loc[pcos_indices, "Follicle No. (R)"] += 7
df.loc[pcos_indices, "Cycle(R/I)"] = 4
# Create visualizations
visualizations = []
# 1. BMI vs Age scatter plot
fig1, ax1 = plt.subplots(figsize=(8, 6))
sns.scatterplot(x="Age (yrs)", y="BMI", hue="PCOS (Y/N)",
data=df, palette=["teal", "plum"], ax=ax1)
ax1.set_title("BMI vs Age by PCOS Status")
visualizations.append(fig1)
# 2. Cycle length vs Age scatter plot
fig2, ax2 = plt.subplots(figsize=(8, 6))
sns.scatterplot(x="Age (yrs)", y="Cycle length(days)", hue="PCOS (Y/N)",
data=df, palette=["teal", "plum"], ax=ax2)
ax2.set_title("Menstrual Cycle Length vs Age by PCOS Status")
visualizations.append(fig2)
# 3. Follicle distribution scatter plot
fig3, ax3 = plt.subplots(figsize=(8, 6))
sns.scatterplot(x="Follicle No. (L)", y="Follicle No. (R)", hue="PCOS (Y/N)",
data=df, palette=["teal", "plum"], ax=ax3)
ax3.set_title("Follicle Distribution (Left vs Right Ovary)")
visualizations.append(fig3)
# 4. Boxplot for Follicle numbers
fig4, ax4 = plt.subplots(figsize=(10, 6))
sns.boxplot(x="PCOS (Y/N)", y="Follicle No. (L)", data=df, palette=["teal", "plum"], ax=ax4)
ax4.set_title("Follicle Count (Left Ovary) by PCOS Status")
visualizations.append(fig4)
# 5. Endometrium thickness boxplot
fig5, ax5 = plt.subplots(figsize=(10, 6))
sns.boxplot(x="PCOS (Y/N)", y="Endometrium (mm)", data=df, palette=["teal", "plum"], ax=ax5)
ax5.set_title("Endometrium Thickness by PCOS Status")
visualizations.append(fig5)
return visualizations
# Helper function to get numerical value for categorical inputs
def get_numerical_value(value, options):
try:
return options.index(value)
except:
return 0
# Helper function to preprocess inputs
def preprocess_inputs(input_dict):
# Convert checkbox values to 0/1
for key in input_dict:
if isinstance(input_dict[key], bool):
input_dict[key] = 1 if input_dict[key] else 0
# Convert blood group to numeric
blood_groups = ["A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"]
if "Blood Group" in input_dict and input_dict["Blood Group"] in blood_groups:
input_dict["Blood Group"] = blood_groups.index(input_dict["Blood Group"])
return input_dict
# Function to process input and make predictions
def predict_pcos(*args):
if model is None:
return "Model not loaded correctly. Please check if model files are available."
try:
# Convert inputs to a dictionary and then DataFrame
input_dict = {feature: value for feature, value in zip(features, args)}
# Preprocess inputs
input_dict = preprocess_inputs(input_dict)
# Convert to DataFrame
input_df = pd.DataFrame([input_dict])
# Print for debugging
print("Input shape:", input_df.shape)
print("Input data types:", input_df.dtypes)
# Make prediction
try:
prediction = model.predict(input_df)[0]
probability = model.predict_proba(input_df)[0]
result = "Positive for PCOS" if prediction == 1 else "Negative for PCOS"
conf = probability[1] if prediction == 1 else probability[0]
return f"{result} (Confidence: {conf:.2f})"
except AttributeError:
# If model is a numpy array, use a simple threshold-based prediction
# This is a fallback if the loaded model is just coefficients
print("Model is not a classifier object, using fallback prediction")
risk_score = np.mean([
input_df["BMI"].values[0] / 30,
input_df["Follicle No. (L)"].values[0] / 15,
input_df["Follicle No. (R)"].values[0] / 15,
(1 if input_df["Cycle(R/I)"].values[0] > 3 else 0)
])
prediction = 1 if risk_score > 0.6 else 0
result = "Positive for PCOS" if prediction == 1 else "Negative for PCOS"
return f"{result} (Risk Score: {risk_score:.2f})"
except Exception as e:
import traceback
traceback.print_exc()
return f"Error making prediction: {str(e)}"
# Function to display visualizations
def show_visualization(visualization_index):
visualizations = create_visualizations()
if 0 <= visualization_index < len(visualizations):
return visualizations[visualization_index]
return None
# Create the Gradio interface
with gr.Blocks(title="PCOS Detection Tool") as app:
gr.Markdown("# PCOS Detection and Analysis Tool")
gr.Markdown("This application uses machine learning to detect Polycystic Ovary Syndrome (PCOS) based on patient data.")
with gr.Tabs():
with gr.TabItem("Make Prediction"):
with gr.Row():
with gr.Column():
gr.Markdown("### Patient Demographics")
age = gr.Slider(18, 50, value=25, label="Age (yrs)")
weight = gr.Slider(40, 120, value=60, label="Weight (Kg)")
height = gr.Slider(140, 190, value=160, label="Height (cm)")
blood_group = gr.Dropdown(["A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"], value="A+", label="Blood Group")
bmi = gr.Slider(15, 40, value=22, label="BMI")
with gr.Column():
gr.Markdown("### Vital Signs")
pulse = gr.Slider(60, 120, value=80, label="Pulse rate (bpm)")
rr = gr.Slider(12, 25, value=16, label="Respiratory Rate (breaths/min)")
systolic = gr.Slider(90, 180, value=120, label="BP Systolic (mmHg)")
diastolic = gr.Slider(60, 120, value=80, label="BP Diastolic (mmHg)")
hb = gr.Slider(8, 18, value=12, label="Hemoglobin (g/dl)")
with gr.Row():
with gr.Column():
gr.Markdown("### Menstrual History")
cycle_length = gr.Slider(21, 45, value=28, label="Cycle length (days)")
cycle_regularity = gr.Radio([2, 4], value=2, label="Cycle Regularity (2=Regular, 4=Irregular)")
with gr.Column():
gr.Markdown("### Physical Measurements")
hip = gr.Slider(30, 60, value=40, label="Hip (inch)")
waist = gr.Slider(20, 50, value=30, label="Waist (inch)")
waist_hip_ratio = gr.Slider(0.6, 1.2, value=0.75, label="Waist:Hip Ratio")
hip_waist_ratio = gr.Slider(1.0, 2.0, value=1.33, label="Hip:Waist Ratio")
with gr.Row():
with gr.Column():
gr.Markdown("### Symptoms")
weight_gain = gr.Checkbox(label="Weight gain", value=False)
hair_growth = gr.Checkbox(label="Excessive hair growth", value=False)
skin_darkening = gr.Checkbox(label="Skin darkening", value=False)
hair_loss = gr.Checkbox(label="Hair loss", value=False)
pimples = gr.Checkbox(label="Pimples", value=False)
with gr.Column():
gr.Markdown("### Lifestyle")
fast_food = gr.Checkbox(label="Fast food consumption", value=False)
regular_exercise = gr.Checkbox(label="Regular exercise", value=False)
with gr.Row():
with gr.Column():
gr.Markdown("### Ultrasound Findings")
follicle_l = gr.Slider(0, 30, value=10, label="Follicle No. (Left)")
follicle_r = gr.Slider(0, 30, value=10, label="Follicle No. (Right)")
avg_fsize_l = gr.Slider(0, 25, value=5, label="Avg. Follicle size (Left) (mm)")
avg_fsize_r = gr.Slider(0, 25, value=5, label="Avg. Follicle size (Right) (mm)")
endometrium = gr.Slider(1, 20, value=8, label="Endometrium (mm)")
with gr.Column():
gr.Markdown("### Hormone Levels")
fsh = gr.Slider(0, 20, value=6, label="FSH (mIU/mL)")
lh = gr.Slider(0, 20, value=7, label="LH (mIU/mL)")
fsh_lh_ratio = gr.Slider(0, 3, value=0.85, label="FSH/LH Ratio")
tsh = gr.Slider(0, 10, value=2.5, label="TSH (mIU/L)")
amh = gr.Slider(0, 10, value=3, label="AMH (ng/mL)")
prl = gr.Slider(0, 30, value=15, label="Prolactin (ng/mL)")
vit_d3 = gr.Slider(0, 100, value=30, label="Vitamin D3 (ng/mL)")
prg = gr.Slider(0, 20, value=5, label="Progesterone (ng/mL)")
with gr.Row():
with gr.Column():
gr.Markdown("### Other Medical")
married_years = gr.Slider(0, 20, value=0, label="Marriage Status (Years)")
pregnant = gr.Checkbox(label="Currently Pregnant", value=False)
abortions = gr.Slider(0, 5, value=0, label="Number of abortions")
rbs = gr.Slider(70, 200, value=90, label="Random Blood Sugar (mg/dl)")
beta_hcg1 = gr.Slider(0, 100, value=5, label="I beta-HCG (mIU/mL)")
beta_hcg2 = gr.Slider(0, 100, value=5, label="II beta-HCG (mIU/mL)")
predict_btn = gr.Button("Predict PCOS Status")
prediction_output = gr.Textbox(label="Prediction Result")
# Connect inputs to prediction function
input_components = [
age, weight, height, bmi, blood_group, pulse, rr, hb, cycle_length,
cycle_regularity, married_years, pregnant, abortions, hip, waist,
waist_hip_ratio, weight_gain, hair_growth, skin_darkening, hair_loss,
pimples, fast_food, regular_exercise, systolic, diastolic, follicle_l,
follicle_r, avg_fsize_l, avg_fsize_r, endometrium, fsh, lh, fsh_lh_ratio,
hip_waist_ratio, tsh, amh, prl, vit_d3, prg, rbs, weight_gain, beta_hcg1, beta_hcg2
]
predict_btn.click(
predict_pcos,
inputs=input_components,
outputs=prediction_output
)
with gr.TabItem("Visualizations"):
gr.Markdown("### PCOS Data Analysis Visualizations")
visualization_choice = gr.Radio(
["BMI vs Age", "Menstrual Cycle Length vs Age", "Follicle Distribution",
"Follicle Count Boxplot", "Endometrium Thickness"],
value="BMI vs Age",
label="Select Visualization"
)
visualization_output = gr.Plot()
visualization_choice.change(
lambda choice: show_visualization(["BMI vs Age", "Menstrual Cycle Length vs Age",
"Follicle Distribution", "Follicle Count Boxplot",
"Endometrium Thickness"].index(choice)),
inputs=visualization_choice,
outputs=visualization_output
)
with gr.TabItem("About PCOS"):
gr.Markdown("""
# Polycystic Ovary Syndrome (PCOS)
Polycystic ovary syndrome (PCOS) is a hormonal disorder common among women of reproductive age.
Women with PCOS may have infrequent or prolonged menstrual periods or excess male hormone (androgen) levels.
## Common Symptoms
- Irregular periods
- Excess androgen (elevated levels of male hormones)
- Polycystic ovaries
- Weight gain
- Acne
- Excessive hair growth (hirsutism)
- Thinning hair or hair loss
- Infertility
## Risk Factors
- Having a mother or sister with PCOS
- Insulin resistance
- Obesity
## Complications
- Infertility
- Gestational diabetes or pregnancy-induced high blood pressure
- Miscarriage or premature birth
- Type 2 diabetes or prediabetes
- Depression, anxiety, and eating disorders
- Sleep apnea
- Endometrial cancer
- Cardiovascular disease
## Treatment
Treatment focuses on managing your individual concerns, such as infertility, hirsutism, acne or obesity.
Specific treatment might involve lifestyle changes or medication.
""")
with gr.TabItem("Debug Info"):
gr.Markdown("### Model and System Information")
debug_output = gr.Textbox(label="Debug Information", value=f"Model type: {type(model).__name__}")
debug_btn = gr.Button("Check Model Status")
def check_model():
try:
if model is None:
return "Model not loaded"
model_info = f"Model type: {type(model).__name__}\n"
# Try to get additional info based on model type
if hasattr(model, 'n_estimators'):
model_info += f"Number of estimators: {model.n_estimators}\n"
if hasattr(model, 'feature_importances_'):
top_features = np.argsort(model.feature_importances_)[-5:]
model_info += "Top 5 important features (indices): " + str(top_features.tolist()) + "\n"
# Check if the model has predict and predict_proba methods
has_predict = hasattr(model, 'predict') and callable(getattr(model, 'predict'))
has_proba = hasattr(model, 'predict_proba') and callable(getattr(model, 'predict_proba'))
model_info += f"Has predict method: {has_predict}\n"
model_info += f"Has predict_proba method: {has_proba}\n"
return model_info
except Exception as e:
return f"Error checking model: {str(e)}"
debug_btn.click(check_model, outputs=debug_output)
# Launch the app
if __name__ == "__main__":
app.launch(share=True, debug=True)