ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

糖尿病预测Notebook实战:从数据预处理到模型部署的完整拆解

2026/10/8 3:01:14 拓冰建站 浏览量
糖尿病预测Notebook实战:从数据预处理到模型部署的完整拆解 简介Diabetes-Predictor 是一份面向数据科学初学者与机器学习实践者的糖尿病风险预测项目资源基于 Pima Indians 等公开生理指标数据集完整演示从数据预处理、探索性分析到建模评估的全流程。压缩包共 4 个文件约 322KB包含 1 个 ipynb 交互式笔记本、1 个 py 脚本、1 个 joblib 训练模型文件与 1 个 md 说明文档分别对应分析主流程、可复用代码、已训练模型与项目说明。目前已有 235 人学习下载。读者可借此掌握缺失值处理、特征工程、逻辑回归与随机森林等模型训练、交叉验证调参及准确率、AUC 等指标评估方法并理解特征重要性与模型解释思路。资源结构紧凑适合作为课程作业、入门练手或公共卫生风险预测场景的参考范例。1. 一份糖尿病预测 Notebook 的拆箱从数据到模型到底能跑出什么糖尿病预测这个题目在 Kaggle 和各类课程作业里被做烂了但真正能拿来复现的完整 Notebook 并不多。Diabetes-Predictor 这个资源的核心价值在于它把从数据加载、特征工程、模型训练到结果可视化的整条链路塞进了一个 Jupyter Notebook 里不需要你去拼凑散落在不同教程里的代码片段。它解决的是“我手上有一份糖尿病相关的结构化数据想快速跑通一个二分类预测流程”这个具体问题。适合谁刚接触机器学习项目实战、需要一份能直接运行并理解每一步在做什么的从业者以及想拿它当模板改造成其他疾病预测任务的工程师。Jupyter Notebook 这个载体本身就意味着你可以逐格执行、逐格调试不用一次性面对几百行脚本。但要注意这类资源的质量参差不齐有些只是把 sklearn 的官方示例换了个数据集有些则真的在特征处理和模型评估上做了细致工作。接下来我会按实际拆解的顺序把这份 Notebook 的结构、关键参数、容易翻车的地方逐一讲清楚。2. 数据加载与特征工程Pima 数据集在 Notebook 里的正确打开方式2.1 数据集来源与字段含义这份 Notebook 大概率使用的是 Pima Indians Diabetes Dataset这是糖尿病预测任务里最常被引用的公开数据集之一。它包含 768 条记录8 个数值型特征1 个二分类标签。字段分别是Pregnancies怀孕次数、Glucose口服葡萄糖耐量试验中的血浆葡萄糖浓度、BloodPressure舒张压、SkinThickness三头肌皮褶厚度、Insulin2 小时血清胰岛素、BMI体重指数、DiabetesPedigreeFunction糖尿病家族史函数、Age年龄以及 Outcome是否患病1 为阳性。在 Notebook 里加载数据通常用 pandas 的 read_csv但这里有个容易被忽略的点原始数据中某些字段的 0 值其实是缺失值的占位符比如 Glucose、BloodPressure、SkinThickness、Insulin、BMI 这五个字段生理上不可能是 0。如果直接把这些 0 当成真实值喂给模型相当于给模型灌了一批噪声准确率会莫名其妙地低一截。import pandas as pd import numpy as np # 加载数据注意原始文件没有表头需要手动指定列名 columns [Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin, BMI, DiabetesPedigreeFunction, Age, Outcome] df pd.read_csv(diabetes.csv, headerNone, namescolumns) # 统计各字段 0 值的数量判断哪些字段存在缺失值占位 zero_counts (df 0).sum() print(zero_counts)这段代码的逻辑很直接先给数据安上列名然后统计每个字段里 0 出现的次数。参数方面headerNone是因为原始文件第一行就是数据不是列名namescolumns把列名一次性指定清楚。执行后你会看到 Glucose、BloodPressure、SkinThickness、Insulin、BMI 这几个字段的 0 值数量从几十到几百不等这就是需要处理的缺失值。常见做法是把这些 0 替换成 NaN然后用中位数或均值填充或者用 KNN 插补。我一般会先看缺失比例如果某个字段缺失超过 30%考虑直接丢掉该字段而不是硬填。2.2 缺失值处理与特征缩放处理缺失值的策略直接影响后续模型的稳定性。Notebook 里如果用的是中位数填充代码大致如下from sklearn.impute import SimpleImputer # 将生理上不可能为 0 的字段中的 0 替换为 NaN zero_fields [Glucose, BloodPressure, SkinThickness, Insulin, BMI] df[zero_fields] df[zero_fields].replace(0, np.nan) # 用中位数填充缺失值 imputer SimpleImputer(strategymedian) df[zero_fields] imputer.fit_transform(df[zero_fields]) # 检查是否还有缺失值 print(df.isnull().sum())这里用SimpleImputer而不是手动fillna好处是它可以在训练集上 fit、在测试集上 transform避免数据泄露。参数strategymedian选择中位数是因为这些医学指标往往有偏态分布均值容易被极端值拉偏。替换完缺失值之后通常还要做特征缩放因为 Glucose 的数值范围在 0 到 200 左右而 DiabetesPedigreeFunction 只有 0 到 2 点几量纲差异会让基于距离的模型比如 KNN、SVM表现很差。标准化用StandardScaler归一化用MinMaxScalerNotebook 里如果用的是逻辑回归或树模型缩放不是必须的但做了也没坏处。from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_scaled scaler.fit_transform(df.drop(Outcome, axis1)) y df[Outcome].values注意fit_transform只应该在训练集上调用测试集要用transform。如果 Notebook 里把整个数据集一起缩放再划分训练测试集那就是典型的数据泄露模型评估结果会虚高。这个坑在后面避坑章节还会展开说。2.3 特征相关性初探在 Notebook 里通常会有一个热力图或者相关性矩阵的输出用来快速判断哪些特征和 Outcome 的相关性更高。Glucose 一般是相关性最高的字段相关系数在 0.45 到 0.5 之间BMI 和 Age 紧随其后。这一步不是为了删特征而是为了心里有数如果某个模型跑出来 Glucose 的权重异常低那大概率是预处理出了问题。用 pandas 的corr()加上 seaborn 的 heatmap 就能出图代码简单但能帮你快速定位数据里的异常关系。3. 模型训练与评估逻辑回归、随机森林在 Notebook 里的参数怎么设3.1 训练集测试集划分与交叉验证Notebook 里最常见的划分方式是train_test_split测试集比例设 0.2 或 0.3随机种子固定一个值保证可复现。但这里有个细节糖尿病数据集的标签分布不算特别均衡阳性样本大约占 35%阴性占 65%。如果直接用随机划分某些折里阳性样本可能偏少导致评估指标波动大。常见做法是加stratifyy参数让训练集和测试集的标签比例与原始数据一致。from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X_scaled, y, test_size0.2, random_state42, stratifyy )参数说明test_size0.2表示 20% 的数据用于测试random_state42是固定随机种子保证每次运行划分结果一样stratifyy确保分层抽样。如果 Notebook 里没加stratify你可以自己补上这是提升评估稳定性的低成本操作。另外如果数据量只有 768 条单次划分的评估结果偶然性较大更稳妥的做法是跑 5 折或 10 折交叉验证用cross_val_score看平均准确率和标准差。from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression lr LogisticRegression(max_iter1000) scores cross_val_score(lr, X_scaled, y, cv5, scoringaccuracy) print(f交叉验证准确率: {scores.mean():.4f} ± {scores.std():.4f})max_iter1000是因为逻辑回归在默认迭代次数下可能不收敛尤其是特征缩放后数据范围变了需要更多迭代来找到最优解。cv5是 5 折交叉验证scoringaccuracy指定评估指标。如果标准差超过 0.03说明模型在不同折上的表现差异较大可能需要检查数据划分或增加正则化。3.2 逻辑回归与随机森林的参数对比Notebook 里通常会跑至少两个模型做对比逻辑回归作为基线随机森林作为非线性模型的代表。逻辑回归的关键参数是正则化强度C默认是 1.0C 越小正则化越强模型越保守C 越大越容易过拟合。随机森林的关键参数是n_estimators树的数量和max_depth树的最大深度。树的数量一般设 100 到 300再多收益递减最大深度如果不设树会一直长到叶子节点纯净容易过拟合常见做法是设 5 到 10 或者用min_samples_leaf控制。from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, confusion_matrix # 逻辑回归 lr LogisticRegression(C1.0, max_iter1000, random_state42) lr.fit(X_train, y_train) lr_pred lr.predict(X_test) # 随机森林 rf RandomForestClassifier(n_estimators200, max_depth6, random_state42) rf.fit(X_train, y_train) rf_pred rf.predict(X_test) # 输出评估报告 print(逻辑回归:) print(classification_report(y_test, lr_pred)) print(随机森林:) print(classification_report(y_test, rf_pred))classification_report会输出精确率、召回率、F1 值和样本量。对于糖尿病预测这种场景召回率比精确率更重要因为漏诊一个阳性患者的代价远大于误诊一个阴性患者。如果 Notebook 里只看了准确率那是不够的准确率在类别不均衡时会骗人。比如一个把所有样本都预测为阴性的模型准确率也有 65%但召回率为 0。所以一定要看分类报告里的 recall 那一列。3.3 模型评估指标的选择与解读除了准确率和召回率ROC 曲线和 AUC 值也是 Notebook 里常见的评估手段。AUC 衡量的是模型区分正负样本的能力0.5 相当于随机猜1.0 是完美区分。糖尿病预测任务里AUC 能到 0.82 到 0.85 就算不错了。画 ROC 曲线用roc_curve和auc两个函数代码不复杂但要注意predict_proba返回的是两列取第二列作为阳性概率。from sklearn.metrics import roc_curve, auc import matplotlib.pyplot as plt rf_probs rf.predict_proba(X_test)[:, 1] fpr, tpr, thresholds roc_curve(y_test, rf_probs) roc_auc auc(fpr, tpr) plt.plot(fpr, tpr, labelfRandom Forest (AUC {roc_auc:.3f})) plt.plot([0, 1], [0, 1], k--) plt.xlabel(False Positive Rate) plt.ylabel(True Positive Rate) plt.legend() plt.show()这段代码里predict_proba(X_test)[:, 1]取的是阳性类别的概率roc_curve返回假阳性率、真阳性率和对应的阈值。AUC 值可以直接从auc(fpr, tpr)算出来。如果 Notebook 里没有画 ROC 曲线建议补上因为这是向别人展示模型区分能力最直观的方式。另外阈值不是固定 0.5你可以根据实际需求调整如果更看重召回率把阈值调低比如 0.4让更多样本被判为阳性。4. 避坑与排查Notebook 跑不通时先看这五条4.1 数据泄露缩放和填充在划分之前做了现象模型在测试集上的准确率异常高比如 0.95 以上但换一批数据或者换个随机种子就掉到 0.7。原因在train_test_split之前就对整个数据集做了fit_transform测试集的信息泄露到了训练过程中。解决先把数据划分成训练集和测试集然后在训练集上fit在测试集上只做transform。填充缺失值同理SimpleImputer的fit只能碰训练集。4.2 逻辑回归不收敛max_iter 默认值太小现象运行逻辑回归时弹出ConvergenceWarning提示迭代次数不够。原因sklearn 的逻辑回归默认max_iter100在特征缩放后或者数据维度较高时不够用。解决把max_iter调到 1000 甚至 2000同时检查特征是否已经标准化。如果调大之后还不收敛可能是特征之间存在严重共线性考虑用L2正则化或者删掉相关性极高的特征。4.3 随机森林准确率虚高没有限制树深度现象随机森林在训练集上准确率接近 1.0但在测试集上只有 0.75 左右。原因max_depth没设树完全生长每个叶子节点都是纯净的模型把训练数据背下来了。解决设置max_depth在 5 到 10 之间或者用min_samples_leaf限制叶子节点的最小样本数比如设 5 到 10。也可以开oob_scoreTrue用袋外样本评估不用单独划测试集。4.4 缺失值填充后分布偏移中位数填充的副作用现象填充缺失值之后某个字段的分布明显向中间集中直方图从双峰变成单峰。原因中位数填充会把所有缺失值塞到同一个数值上如果缺失比例高会人为制造一个尖峰。解决如果缺失比例超过 20%考虑用 KNN 插补或者迭代插补保留更多原始分布信息。或者直接加一个二值特征标记该字段是否缺失让模型自己学缺失模式。4.5 Notebook 单元格执行顺序混乱变量覆盖现象重新运行某个单元格后结果变了或者报NameError。原因Jupyter Notebook 允许乱序执行前面的单元格可能用了后面才定义的变量或者同一个变量名被多次赋值。解决每次改完代码从第一个单元格重新跑一遍用Kernel - Restart Run All。另外变量命名尽量带前缀比如X_train_scaled、rf_model避免覆盖。5. 从 Notebook 到可复用脚本把预测流程封装成函数5.1 把预处理和训练串成 PipelineNotebook 里一步步写虽然直观但每次换数据都要手动改一堆单元格。更工程化的做法是用 sklearn 的Pipeline把填充、缩放、模型训练串起来这样交叉验证和网格搜索都能直接套用不用担心中间步骤的数据泄露。from sklearn.pipeline import Pipeline from sklearn.model_selection import GridSearchCV pipe Pipeline([ (imputer, SimpleImputer(strategymedian)), (scaler, StandardScaler()), (clf, RandomForestClassifier(random_state42)) ]) param_grid { clf__n_estimators: [100, 200, 300], clf__max_depth: [4, 6, 8, None], clf__min_samples_leaf: [1, 3, 5] } grid GridSearchCV(pipe, param_grid, cv5, scoringroc_auc, n_jobs-1) grid.fit(X_train, y_train) print(f最佳参数: {grid.best_params_}) print(f最佳 AUC: {grid.best_score_:.4f})Pipeline 的好处是每一步的fit只在训练折上调用transform在验证折上调用彻底杜绝数据泄露。GridSearchCV的scoringroc_auc比准确率更适合类别不均衡的场景n_jobs-1表示用满所有 CPU 核心加速搜索。参数网格里clf__前缀是 Pipeline 的命名规则表示该参数属于clf这一步。搜索完成后best_params_直接给出最优组合best_score_是交叉验证的平均 AUC。5.2 模型持久化与单条预测训练好的模型要存下来才能在实际中调用用joblib比pickle更高效尤其是模型里有大量 numpy 数组时。import joblib # 保存模型 joblib.dump(grid.best_estimator_, diabetes_predictor.pkl) # 加载模型 loaded_model joblib.load(diabetes_predictor.pkl) # 单条样本预测 sample np.array([[2, 120, 70, 25, 100, 28.5, 0.5, 35]]) prediction loaded_model.predict(sample) probability loaded_model.predict_proba(sample)[0, 1] print(f预测结果: {阳性 if prediction[0] 1 else 阴性}) print(f阳性概率: {probability:.4f})单条样本的输入顺序必须和训练时的特征顺序完全一致否则预测结果毫无意义。predict_proba返回的是二维数组取[0, 1]拿到阳性概率。如果概率在 0.4 到 0.6 之间说明模型对这个样本不太确定实际应用中应该结合其他检查手段而不是只看模型输出。5.3 特征重要性分析与业务解释随机森林自带feature_importances_属性可以直接看哪些特征对预测贡献最大。这一步在 Notebook 里通常用条形图展示但更重要的是理解背后的业务含义。import pandas as pd feature_names [Pregnancies, Glucose, BloodPressure, SkinThickness, Insulin, BMI, DiabetesPedigreeFunction, Age] importances grid.best_estimator_.named_steps[clf].feature_importances_ feat_imp pd.Series(importances, indexfeature_names).sort_values(ascendingFalse) print(feat_imp)named_steps[clf]是从 Pipeline 里取出分类器这一步然后拿feature_importances_。通常 Glucose 会排在第一BMI 和 Age 紧随其后。如果某个特征重要性异常高但业务上说不通比如 SkinThickness 排到了前三那就要回头检查这个字段的缺失值处理是不是出了问题。特征重要性不是因果推断它只说明模型在划分节点时用了多少这个特征不代表这个特征就是致病原因。5.4 一个容易忽略的验证习惯每次改完预处理逻辑或者模型参数不要只看一次划分的测试集结果。我一般会强制跑三遍不同随机种子的train_test_split再看交叉验证的均值和标准差。如果三次结果波动超过 0.05说明模型对数据划分太敏感要么数据量不够要么特征工程有问题。从那以后我每次交付模型之前都会把cross_val_score和classification_report一起跑一遍确认召回率和 AUC 都在合理范围内才收工。希望这份拆解能帮到你少走一些我踩过的弯路。本文还有配套的精品资源点击获取