☰
基于机器学习的糖尿病预测项目实践:从数据清洗到模型调优
2026/10/17 9:27:30 网站建设 项目流程

做毕设的时候,我选的题目是基于机器学习与大数据的糖尿病预测。选这个题,说句实话,一开始想的确实是“数据公开、算法成熟、容易出结果”,但真正做下来之后我发现,这个选题能把我大学四年学的东西全部串起来——从数据清洗、特征工程、到模型训练、评估调优,再到最后的可视化展示,几乎每个环节都有值得深挖的空间。

这篇文章我想以一个刚把这个项目完整做下来的学生视角,把整个项目从选题思路到模型落地的每个环节都讲透。适合正在纠结毕设选题的同学,也适合那些对机器学习医疗应用感兴趣、想找个项目练手的朋友。我会把我在实际开发中踩过的坑、反复调整的方案、以及最后为什么这么设计的思考过程都写出来,尽量让这篇文章能直接作为你复现项目的参考。

1. 项目整体设计与技术选型思路

1.1 课题定位:为什么是糖尿病预测

先说选题逻辑。毕设选题最怕两种:一种是太大,做不完;一种是太小,撑不起工作量。糖尿病预测恰好卡在一个很舒服的位置上。

从应用背景看,糖尿病属于慢性代谢类疾病,相关公开数据比较多,特征变量也相对完整。从技术角度看,这是一个典型的二分类监督学习任务——根据患者的基础信息(年龄、体重指数、血压、血糖等)判断是否患病。任务明确,评价指标明确,模型效果也容易量化。

更重要的是,这个方向有清晰的业务价值。预测模型的本质不是在“诊断”,而是在“筛查”——在大规模人群中找出高风险人群,提醒他们提前干预。这个定位让项目的意义一下子从“完成一个算法Demo”上升到了“解决一个实际健康管理问题”。

我建议把这个“筛查 vs 诊断”的差异写进开题报告和最终论文里,这是一种很讨喜的定位方式,因为答辩老师不会纠结你模型的准确率是不是100%,而是会认可你对应用场景的准确理解。

1.2 技术栈选型:整个框架怎么搭

这个项目的技术栈,我总结下来是六个字:够用、好讲、可扩展。

数据处理层面,主力是Pandas和NumPy。数据量如果只有几千到几万条,根本不需要上Spark,用Pandas做清洗和特征工程效率最高,也最容易调试。但对于“大数据”这个点,我做了两层处理:第一,把所有数据处理流程封装成模块化管道,模拟大数据平台的数据流处理思路;第二,引入分布式计算框架对数据做并行处理演示,虽然我的实际数据量不大,但处理逻辑完全按照大规模数据的思路来设计,这样在论文里也好展开。

模型层面,我同时实现了三类算法:逻辑回归作为基线模型,随机森林作为传统集成代表,XGBoost作为梯度提升代表。三个模型做横向对比,既有理论深度又能体现工作量。

部署展示层面,用一个轻量级Web框架搭了简单的预测服务,用户输入指标数据,后端调用训练好的模型返回风险概率。这块内容在答辩演示环节特别加分,因为很多毕设做完只有一个Jupyter Notebook,能拿出一个可交互的Demo,评审印象会好很多。

1.3 整体流程设计的思考

整个项目的流程在心里要非常清晰,这是答辩时我最深的体会。大致分为五步:数据获取、数据预处理、特征工程、模型训练与调优、模型评估与部署展示。

每一步之间要形成清晰的上下游关系。比如数据清洗的结果直接影响特征工程,而特征工程的结果又直接影响模型的上限。我当时的处理方式是每一步都写一个独立的工具函数,并在函数文档里记录输入输出的格式,这样调试的时候能很快定位问题,写论文的时候也容易组织章节。

归根结底,技术选型不是越新越好,而是要让每一步都有据可查、有逻辑可循。答辩老师不一定懂你的每个参数,但他一定能看出你的流程是否完整、逻辑是否自洽。

2. 数据获取与预处理实操

2.1 数据源选择与字段认识

我最终用的是一份公开的糖尿病数据集,样本量在几千条级别。这里有几个关键判断。

第一,公开数据集一定要找有“背景文档”的,也就是数据来源、采集标准、字段含义都有说明的数据集。否则你连“血糖浓度”“2小时血清胰岛素”这种字段到底怎么测的都不知道,做完也没法往论文里写。

第二,数据量不是越大越好。几千条数据对毕设来说完全够用,关键是数据质量。我当时检查数据分布,发现样本中负类(未患病)数量偏多,属于轻度不平衡,这个问题在后面模型评估时要重点处理。

第三,如果条件允许,可以尝试去公开的医疗数据共享平台找更多维度的数据做补充,但要注意:不同来源的数据字段可能对不上,整合成本远比想象高。我最后放弃了这个想法,因为数据量上去了,但“脏”的程度也上去了。

这份数据集的主要字段大概如下,先对字段有认知再动手处理,能少走很多弯路:

字段含义处理注意点
血糖浓度口服葡萄糖耐量试验2小时后的血糖值0值视为缺失,需填充
胰岛素2小时血清胰岛素水平0值比例偏高,需重点关注
BMI体重指数,衡量肥胖程度生理范围约15~50,超范围需排查
血压舒张压,单位mm Hg0值异常,需处理
年龄患者年龄通常为21~80岁
标签是否患病(0/1)正负样本不平衡,评估需注意

2.2 数据清洗:最容易翻车的细节

数据清洗是最磨人、但最考验基本功的环节。

首先是缺失值处理。糖尿病数据集里,有几个字段经常会存在0值,但这些字段在医学上不可能为0,比如血糖浓度、BMI、血压。这其实是“以0填充缺失值”的常见情况。我当时的处理方案是:先统计每个特征的0值比例,再把0值视为缺失值,用均值或中位数填充。对于皮褶厚度和胰岛素这类0值比例较高的字段,我选择了基于KNN的缺失值填充法,因为这种数据往往存在一定的分布结构,KNN比简单均值更能保留特征之间的相关性。

其次是异常值处理。我用箱线图法识别出了少量极端值,比如BMI高达70多、血糖值明显超出生理范围。这些数据点直接删除,因为它们大概率是录入错误,留在数据集里会严重影响模型。

关于标准化,这里有个容易弄反的地方:逻辑回归和基于距离计算的算法对特征的尺度非常敏感,需要做标准化;而树模型(随机森林、XGBoost)对尺度不敏感,标准化与否影响不大。我的处理是:统一做标准化,但模型对比时分别储存两份数据集,一份标准化后的、一份原始尺度的,方便分别喂给不同模型。

2.3 特征工程:拉开差距的环节

特征工程是这个项目里最能拉开差距的环节,也是论文里可以重点写的部分。

我保留了原始特征的组合,同时构造了几个新的特征。比如“BMI和年龄的交互项”——二型糖尿病的发病风险会随着体重和年龄同时增长而显著上升,用交互项可以把这种联合效应显式表达出来。再比如把血压字段拆成收缩压和舒张压两个独立特征,虽然原始数据可能已经分开,但要确认它们进入模型时是作为两个特征而不是一个字符串。

另外一个很重要的操作是特征相关性分析。我画了相关性热力图,发现血糖浓度与标签的相关性最高,其次是BMI。这一步不仅帮我理解数据,也能在论文的“探索性数据分析”章节里放图,是加分的展示材料。

我自己比较后悔的一点是:刚开始做特征工程时太激进,一次性构造了十几个特征,结果模型没有明显提升,反而让训练时间变长。后来我用了减法思维——先加再减,对特征做重要性排序后逐一去掉低重要性特征。最终保留的特征数量大概在10个左右,模型效果反而更稳定。

3. 核心模型实现与训练调优

3.1 逻辑回归:基线的价值

任何分类项目,我都强烈建议先跑一个基线模型。逻辑回归在这类二分类问题里就是最好的基线。

为什么?因为它简单、可解释、训练快。如果连逻辑回归都跑不出一个像样的结果,那要么是数据有问题,要么是特征工程没做好,这时候直接上复杂模型只会浪费时间。

我实现的逻辑回归版本,加入了L2正则化和随机梯度下降优化。L2正则化的作用是对权重做惩罚,防止模型在特征较多时过拟合。这里有一个可调的重要参数是C值(正则化强度的倒数),我用网格搜索在0.001到100的对数范围内寻优。

我当时的关键代码大概是这样的:

from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler # 标准化处理 scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) # 基线模型,C是正则化强度倒数 model = LogisticRegression(C=0.1, penalty='l2', max_iter=1000) model.fit(X_train, y_train)

逻辑回归的另一个价值在于可解释性。训练完后,模型给每个特征一个权重,权重的正负和大小直接告诉我们该特征对患病风险是正向还是负向影响,影响程度多大。这在我后面写分析结论时起了大作用。

3.2 随机森林与XGBoost的实战调参

随机森林的核心是“集成学习”——用多棵树投票。它的优点是抗过拟合能力强,对特征尺度不敏感,几乎不需要太多特征工程就能获得不错的效果。

我调参的重点放在三个地方:树的数量n_estimators、树的最大深度max_depth、最小样本划分数min_samples_split。树的数量太大会导致训练时间变长但效果饱和,我实测在300棵左右时收益已经很稳定;树的深度太容易过拟合,我控制在5到10之间。

XGBoost的调参则要注意另一组参数:学习率、树深度、子采样比例和正则化参数。学习率我初始设为0.1,配合早停机制;调高树深度会增强模型表达力但容易过拟合。

import xgboost as xgb model = xgb.XGBClassifier( learning_rate=0.1, max_depth=6, n_estimators=300, subsample=0.8, reg_lambda=1.0 ) model.fit(X_train, y_train, eval_set=[(X_test, y_test)], early_stopping_rounds=20)

一个实操细节:XGBoost对缺失值有内置处理机制,但我还是选择提前处理好缺失值,因为我的数据量不大,尽可能保留信息更重要。

3.3 交叉验证与网格搜索的正确打开方式

交叉验证是评估模型泛化能力的核心手段。我用的是5折分层交叉验证——分层的意思是保证每一折里正负样本的比例与总体一致,这对不平衡数据尤其重要。

网格搜索我放在调参的最后一环。为什么?因为网格搜索是组合爆炸,特征处理方式和算法参数再叠在一起,搜索空间会非常大,跑一轮要很久。

我的做法是分阶段进行:先用经验范围粗调,锁定几个关键参数的大致区间,再在小区间内做细网格搜索。比如先固定树深度为5、6、7跑一遍,选出最好的是6,再在这个值附近做候选集为{5, 6, 7}的精细搜索。在评分指标上,我没有用准确率,而是用AUC,因为AUC对不平衡数据更稳健,也更符合医疗筛查场景的需求。

4. 模型评估与结果分析

4.1 评估指标怎么选:别被准确率带偏

对于医疗类二分类任务,最忌讳的就是只看准确率。举一个极端例子:假如数据集中95%的人是未患病,模型只要全预测为未患病,准确率就有95%,但这个模型毫无价值。

我使用的核心评估指标组合是:准确率、精确率、召回率、F1分数、AUC值、混淆矩阵。其中在这个筛查场景下,我特别关注召回率——也就是真正患病的人里有多少被模型找出来了。因为在筛查场景里,“漏诊”的代价远大于“误报”,宁可把健康人误报到高危列表里安排二次检查,也不能让真正的患者被漏掉。

三个模型对比下来,我最后的AUC从0.82到0.88不等,XGBoost整体最优,随机森林紧随其后,逻辑回归作为基线也达到0.83,说明特征工程基础打得不错。

4.2 混淆矩阵与阈值灵敏度分析

模型默认以0.5作为正负类划分阈值,但这个阈值对不平衡数据不一定最优。我尝试在0.3到0.7之间逐点调整阈值,观察召回率和精确率的变化,画出了帕累托曲线。这一步在论文里很出彩,因为它体现了你对模型输出有更深的理解,而不是拿一个默认参数就交差。

实际操作中,我用训练集调整阈值,再用测试集验证最终选择。通过这种方式,我把召回率从0.78提升到了0.84,同时也知道代价是精确率下降了几个百分点。这个取舍过程本身就是医疗场景“敏感性优先”的最好佐证。

4.3 特征重要性与模型可解释性

我用了XGBoost内置的特征重要性输出,结合SHAP值分析工具做了可解释性分析。SHAP能告诉我们每个特征对单个样本预测结果的正负贡献,比单纯看特征重要性更细。

分析结果非常直观:血糖浓度、BMI、年龄排在前三,这和医学常识高度一致。能拿到与临床共识相印证的结果,对答辩来说是很有说服力的论据。我之前担心的“模型黑箱”问题,在做了SHAP之后基本消解了,评委看到那些图表时明显更有兴趣。

5. 常见问题与避坑指南

5.1 流程先跑通,再谈优化

如果你复现这个项目,我最大的建议是:先把整个流程从数据到模型评估完整跑通,哪怕效果一般,再开始优化。很多人一开始就在调参数上死磕,结果连数据管道都没理顺。

我自己的经历是:第一版模型跑出来AUC只有0.79,当时很沮丧,但后来发现只是特征没有标准化,逻辑回归的收敛出了问题。思路通了之后,同一份代码AUC就到了0.83。这说明很多时候瓶颈不在于模型选得不好,而在于数据管道有bug。

5.2 数据不平衡怎么兜底

如果训练集里负样本远多于正样本,除了改用AUC评估,还可以尝试正样本加权或过采样方法。我在实验里用过SMOTE算法来合成少数类样本,效果有一定提升,但要注意:SMOTE合成样本时如果特征空间重叠严重,可能引入噪声。我后来把加权方案和SMOTE方案做了对比,最终选择两者结合的方式。

具体做法是:给少数类样本一个更高的类别权重,同时用SMOTE做轻度过采样,把正负比例拉到一个更舒服的区间。这样既保留了原始数据的信息,又缓解了模型对多数类过拟合的问题。

5.3 答辩时容易被追问的三个问题

答辩时容易被追问的问题我提前梳理了一下。

第一个是“你这个预测模型和医生诊断的区别是什么”。我的回答是:模型定位是筛查工具,输出的是风险概率和风险因素排序,帮助医生提高效率,而不是替代诊断。

第二个是“数据量这么小,说是大数据是不是名不副实”。我的回答是:项目重点在于完整的大数据处理流程和方法论,并且已经用分布式方案跑通了全流程,未来接入更大规模数据时可以无缝切换。

第三个是“为什么不直接用深度学习”。我的回答是:在数据量只有几千条的医疗表格型数据上,树模型通常比深度学习效果更好、训练成本更低、可解释性更强。我还补充了在小样本表格数据场景下,这是业界的常见判断。

5.4 时间管理与环境依赖的教训

最后说一点进度管理的心得。我把项目拆成了四个阶段:数据准备、建模、调优评估、部署展示,每个阶段预留至少一周的缓冲。实际上大部分时间都消耗在数据清洗和调试环境上,真正训练模型反而很快。

有一次深夜调试环境,几行依赖版本冲突问题耗了一整晚。我最后的经验是:每完成一个阶段就固定环境依赖版本,写进记录文件里,并且把关键代码提交版本控制。这样即使环境崩溃,也能快速恢复。

另一个让人印象深刻的点是,数据清洗阶段的输出一定要可视化检查一遍,比如画出每列特征的分布图、缺失值比例图。不要觉得这一步多了,很多莫名其妙的问题,根源都在数据里。你多花半小时看数据分布,可能就省下后面好几天的排查时间。

做这个项目给我最大的感受是:毕设不只是一个期末产物,它更像是把课本知识和真实问题之间的墙敲掉的过程。从最初想“随便找个数据集跑跑模型就交差”,到后来认认真真做特征工程、反复调整阈值、用SHAP解释模型,我在这中间学到的不是某一个算法的用法,而是如何系统地思考一个数据问题。如果你也准备做类似方向,我建议你从选题到每一步实验都留下记录,遇到问题先复盘数据管线,再考虑算法,这条路走下来,你会发现自己收获的东西比想象中多得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询