A diabetes risk predictor trained on the Pima Indians dataset — with hyperparameter tuning, ROC curve, and a predict_patient() function for new cases.
The Pima Indians dataset has 768 rows and 8 health features. Some zero values are actually missing data — we replace them.
import pandas as pd
import numpy as np
# Download from: https://www.kaggle.com/datasets/uciml/pima-indians-diabetes-database
df = pd.read_csv('diabetes.csv')
print(df.head())
print(df['Outcome'].value_counts()) # 0 = no diabetes, 1 = diabetes
# Replace biologically impossible zeros with NaN, then fill with median
zero_cols = ['Glucose','BloodPressure','SkinThickness','Insulin','BMI']
df[zero_cols] = df[zero_cols].replace(0, np.nan)
df.fillna(df.median(numeric_only=True), inplace=True)
print(df.isnull().sum()) # Should all be 0 now
Use GridSearchCV to find the best hyperparameters automatically.
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
X = df.drop('Outcome', axis=1)
y = df['Outcome']
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
pipeline = Pipeline([
('scaler', StandardScaler()),
('clf', GradientBoostingClassifier(random_state=42)),
])
params = {
'clf__n_estimators': [100, 200],
'clf__learning_rate': [0.05, 0.1],
'clf__max_depth': [3, 4],
}
grid = GridSearchCV(pipeline, params, cv=5, scoring='roc_auc', n_jobs=-1)
grid.fit(X_train, y_train)
print("Best params:", grid.best_params_)
print(f"Best CV AUC: {grid.best_score_:.4f}")
print(f"Test accuracy: {grid.score(X_test, y_test):.4f}")
Best params: {'clf__learning_rate': 0.1, 'clf__max_depth': 3, 'clf__n_estimators': 200}
Best CV AUC: 0.8412
Test accuracy: 0.7922The ROC curve shows the trade-off between sensitivity and specificity at different thresholds.
from sklearn.metrics import RocCurveDisplay, classification_report
import matplotlib.pyplot as plt
best_model = grid.best_estimator_
y_pred = best_model.predict(X_test)
print(classification_report(y_test, y_pred, target_names=['No Diabetes','Diabetes']))
fig, ax = plt.subplots(figsize=(6,5))
RocCurveDisplay.from_estimator(best_model, X_test, y_test, ax=ax)
ax.set_title('Diabetes Predictor — ROC Curve')
plt.tight_layout()
plt.savefig('roc_curve.png', dpi=120)
plt.show()
Wrap the model in a function that takes a patient dict and returns a risk assessment.
def predict_patient(patient_dict):
cols = ['Pregnancies','Glucose','BloodPressure','SkinThickness',
'Insulin','BMI','DiabetesPedigreeFunction','Age']
row = pd.DataFrame([patient_dict])[cols]
prob = best_model.predict_proba(row)[0][1]
risk = 'HIGH' if prob > 0.5 else 'LOW'
print(f"Diabetes risk: {risk} (probability: {prob:.1%})")
return prob
predict_patient({
'Pregnancies': 2, 'Glucose': 148, 'BloodPressure': 72,
'SkinThickness': 35, 'Insulin': 0, 'BMI': 33.6,
'DiabetesPedigreeFunction': 0.627, 'Age': 50,
})
Diabetes risk: HIGH (probability: 83.1%)
You trained, tuned, and deployed a diabetes risk model in under 60 lines. The same GridSearchCV + Pipeline pattern applies to any classification problem — just swap the dataset and the estimator.
Spotted a bug, broken code, or something that doesn't look right? Tell us what's off and we'll fix it.