news 2026/10/10 9:43:56

基于机器学习的肥胖预测系统:从决策树到深度学习的模型对比与Django实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于机器学习的肥胖预测系统:从决策树到深度学习的模型对比与Django实现

做毕设选这个题目的时候,我其实有点犹豫。机器学习、决策树、深度学习、Django,几个词拼在一起看似很“热门”,但担心会不会只是一个技术堆砌的大杂烩。做完之后回头想,这个项目真正值钱的地方不在于用了多少算法,而在于它完整覆盖了一条从数据理解、特征工程、模型对比到Web系统落地的工业级流水线。你要做毕业设计、找实习作品、或者想入门数据科学又不想只停留在跑通Notebook,这个项目都能给你一个非常扎实的落脚点。

我能用一句话说清楚这东西是什么:用机器学习模型对肥胖成因做预测分析,并基于决策树、集成模型和深度学习算法做横向对比,最后用Django把模型封装成可以在浏览器里直接使用的Web系统。它能做什么?采集一个人的饮食、运动、遗传等特征,预测肥胖等级,还能解释哪些因素影响最大。适合谁?计算机、数据科学、软件工程方向的同学,尤其想走机器学习工程路线但手里缺一个“能演示、能答辩、能写论文”项目的朋友。


1. 毕设选题不能只看热度,更要看“能不能做完”

很多人选“基于机器学习的XX预测系统”这类题目,是为了蹭热度,但真正动手才发现数据集难找、特征太乱、算法结果像玄学、Web端又不会集成。我为什么说“肥胖成因分析与对比”这个方向是相对稳妥的?因为它在数据、算法、系统三个维度上都刚好卡在“有挑战但可控”的位置。

1.1 选题逻辑:一个题目同时覆盖数据、算法、系统的闭环

肥胖成因预测本质上是一个有监督分类问题,目标是根据个体特征预测其肥胖等级,常见分类有 Insufficient_Weight、Normal_Weight、Overweight_Level_I、Obesity_Type_I 等。这个场景在公开数据领域有现成的、质量不错的数据集,比如UCI机器学习库中的Obesity Dataset,样本量不大(2000多行),特征维度适中(16列左右),既有连续变量又有类别变量,还带明显的类别不平衡。这些特点恰好让它成为教学、毕设场景的“黄金数据”。

更妙的是,肥胖成因本身存在多因素耦合:遗传(家族史)、饮食习惯、运动频率、作息、交通方式都会影响结果。它不是简单的线性关系,所以用决策树、随机森林、甚至深度神经网络来做都有发挥空间,且不同模型的表现差异能直观展示“为什么需要算法对比”。这比单纯拿鸢尾花数据集做的“假项目”要有说服力得多。

1.2 系统目标和技术路线:不只是“算法跑个分”

我给自己定的目标是:做一个能实际使用的“个人肥胖风险分析系统”,而不是交一个训练好的模型文件完事。系统要能完成四件事:

  1. 用户录入个人基本信息和生活习惯;
  2. 后台调用训练好的机器学习模型,实时输出肥胖等级预测;
  3. 通过决策树可视化或特征重要性,解释“为什么是这个结果”;
  4. 展示不同算法(决策树、随机森林、XGBoost、MLP)在同一测试集上的性能对比。

技术路线也很直接:Python 3.8 + Django 3.2 + pandas + scikit-learn + TensorFlow/Keras + 前端Bootstrap。有人会问,深度学习在大数据场景里不是很吃资源吗?我这里的“深度学习”并没有上大模型,而是针对表格数据设计了一个MLP多层感知机,参数量十万以内,普通笔记本就能跑。这部分后面会细说。


2. 数据处理:机器学习里的“七分靠数据”不是玩笑

无论你打算用决策树还是深度学习,数据没洗干净,后面所有模型都是自欺欺人。这个项目里的原始数据是英文编码的,比如字段FAF、FCVC、CH2O,第一次打开可能看得一脸懵。需要先理解每个字段的业务含义,再决定怎么清洗和构造特征。

2.1 字段理解与业务映射

我用的UCI肥胖数据集字段大致如下:

字段含义类型
Gender性别类别
Age年龄连续
Height / Weight身高(m)、体重(kg)连续
family_history_with_overweight是否有肥胖家族史二分类
FAVC是否频繁吃高热量食物二分类
FCVC吃蔬菜的频率(1-3分)离散
NCP正餐次数连续
CAEC两餐之间是否吃东西类别
CH2O每天饮水升数连续
SCC是否监测卡路里摄入二分类
FAF每周运动频率连续
TUE每天使用电子设备时间连续
CALC饮酒频率类别
MTRANS常用交通方式类别
NObeyesdad体重等级标签分类目标

这里有个很重要的业务理解:Height和Weight可以合并计算出BMI,而BMI和最终的肥胖等级标签存在极强的相关关系。如果直接把BMI作为一个特征输入模型,模型很容易“作弊”——几乎不用看其他特征就能靠BMI猜出肥胖等级,准确率会虚高。但在实际应用中,BMI本身就是肥胖等级划分标准的一部分,这么做会导致数据泄露,掩盖真实成因。所以我在特征工程中会选择不使用BMI,或者有意保留原始身高体重,让模型从身高体重、生活习惯、遗传因素的组合中学到因果关系。这一点在论文里是很好的讨论素材。

2.2 清洗与特征工程实操

清洗步骤不复杂,但一个都不能少:

  • 检查缺失值,通常这个数据集没有缺失,但必须验证;
  • 类别变量编码:二分类用LabelEncoder,多分类用OneHotEncoder,避免给类别强加数字大小顺序;
  • 连续变量标准化:决策树不要求标准化,但MLP和K近邻需要;所以我都做了一遍标准化并保存scaler对象,供预测时复用;
  • 划分训练集和测试集:按80/20,设定random_state=42保证可复现;
  • 类别不平衡处理:肥胖等级中Normal_Weight和Obesity_Type_I样本偏多,而Insufficient_Weight较少,直接用accuracy容易被“多数类”迷惑。这里我用SMOTE做少数类过采样,注意只在训练集上做,不要在测试集上做,否则会数据泄漏。

2.3 最容易犯的错误:特征顺序不一致

这个坑我踩得很重。训练模型时,我用pandas的DataFrame传入X_train,模型记住了特征的顺序;但在Django里接收前端表单数据后,如果手动拼dict,稍不留神字段顺序就和训练时不一致,那模型预测结果就是一团乱码。解决办法是:训练时把特征列表单独保存为一个变量,比如feature_columns = [...],用joblib保存特征列表文件;在Django预测时,先按这个列表创建空DataFrame,再逐一填充,顺序绝对不能临时拼。


3. 从决策树到深度学习:算法选型与对比策略

这一部分是项目的核心灵魂。很多人把多个模型跑一遍,比个AUC就完事,但“为什么选这个模型”“怎么调参”“结果差异说明了什么”才是答辩时老师最想听的。

3.1 决策树分类器:可解释性拉满的基线模型

肥胖成因分析最看重解释性,比如“爱吃高热量食物且缺乏运动的人,更可能肥胖”这种规则,决策树天然能输出。我选用的CART决策树,核心思想是每次选一个特征和切分点,让切分后子节点的Gini系数下降最大;递归下去,长出一棵树。

决策树有个好处:不需要太多预处理,类别编码后就能直接训练,计算也快。但裸的决策树非常容易过拟合,深度设到5的时候甚至能记住噪声。我实验里,默认参数的决策树准确率约70%,但决策边界很碎;限制max_depth=5、min_samples_split=10后,准确率稍有下降,但泛化能力明显增强。这也能引出“树模型剪枝”的讨论。

补充说明:用Graphviz导出树的可视化结构,在Django前端展示成图片,效果比干巴巴的特征重要性柱状图好得多。

3.2 随机森林与XGBoost:用集成思路甩开单棵树的瓶颈

单棵决策树不稳定,稍微改一点样本结果就变。随机森林的思路是**“三个臭皮匠顶个诸葛亮”**:训练很多棵用随机子样本、随机特征子集构建的树,投票决定结果。这样方差变小,能有效抑制过拟合。

XGBoost则是用梯度提升的思想去“纠错”:每一棵新树都在拟合前面所有树预测结果的残差。在表格数据上,XGBoost往往是性价比最高的选择。我对比下来:

模型准确率F1加权AUC宏平均训练耗时
决策树(剪枝)0.780.770.92秒级
随机森林(500棵树)0.860.850.98秒级
XGBoost(默认)0.890.880.99秒级
MLP(两隐层)0.880.870.98分钟级

这里有个值得注意的现象:XGBoost和MLP表现差距不大,甚至在个别类别上树模型更稳。原因在于表格数据有大量离散化、数值稀疏的特征,树模型对特征变换的适应机制更好;深度学习更擅长图像、语言这种稠密高维数据。但MLP的加入能在论文里引出“神经网络在结构化数据上的边界”这一深度讨论,这是拿高分的关键。

3.3 用Keras搭一个能跑通的MLP模型

深度学习部分不用太华丽,我用了一个三层MLP:

from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout, BatchNormalization from tensorflow.keras.callbacks import EarlyStopping model = Sequential([ Dense(64, activation='relu', input_shape=(X_train.shape[1],)), BatchNormalization(), Dropout(0.3), Dense(32, activation='relu'), BatchNormalization(), Dropout(0.2), Dense(7, activation='softmax') ]) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) early_stop = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True) history = model.fit(X_train_scaled, y_train_encoded, validation_split=0.15, epochs=200, batch_size=32, callbacks=[early_stop], verbose=1)

注意三个细节:

  1. 标准化:一定要用训练集的scaler去transform测试集,不能重新fit,否则信息泄漏;
  2. EarlyStopping:早停是防止过拟合最实用的手段,看val_loss而非val_accuracy;
  3. 类别的编码:标签需要变成0到6的整数序列,预测结果再映射回原来的类别名。

3.4 模型对比怎么才说服力

对比不能只看准确率,因为样本不平衡时准确率会骗人。我最终报告里放了四类指标:准确率、加权精确率、加权召回率、加权F1,还有一个“宏平均AUC”。另外做了5折交叉验证,报告均值±标准差,避免因为固定训练测试集划分产生偏差。这样做完之后,你会发现不同模型在不同肥胖等级上的表现差异很有意思,比如深度学习对Obesity_Type_II的召回率可能更高,而XGBoost在整体平衡性上更优。


4. Django系统实现:把模型从Jupyter搬到Web

算法跑完只是开始。有相当多同学卡在“模型怎么让人用起来”这一步,而Django正好解决了这个难题。项目里我用Django写了一个MVT架构的Web应用,让用户通过表单输入数据,后台调用模型,返回结果和解释。

4.1 系统页面与交互设计

我做了一个很朴素但完整的系统,包含这些页面:

  • 首页:项目介绍、算法对比图表总览;
  • 预测页面:表单包含所有输入字段,每个字段带提示;
  • 结果页:显示预测的肥胖等级、各类别概率条形图、决策树路径解释;
  • 对比页面:用柱状图/折线图展示各模型评估指标。

前端用了Bootstrap和ECharts,图表数据由Django视图序列化为JSON传给页面。这里关键是接口设计要稳:前端只管收集表单,后端统一校验和封装,最后返回一个JSON结构,包括prediction、probability、explanation。

4.2 模型加载与预测的完整流程

我在ml_utils/predictor.py里封装了统一预测接口:

import joblib import numpy as np import pandas as pd from tensorflow.keras.models import load_model class ObesityPredictor: def __init__(self): self.feature_columns = joblib.load('models/feature_columns.pkl') self.scaler = joblib.load('models/scaler.pkl') self.smote_encoder = joblib.load('models/label_encoder.pkl') self.xgb_model = joblib.load('models/xgb_model.pkl') self.mlp_model = load_model('models/mlp_model.h5') def _build_frame(self, form_dict): df = pd.DataFrame([{col: form_dict.get(col, 0) for col in self.feature_columns}]) df = df[self.feature_columns] return df def predict(self, form_dict): df = self._build_frame(form_dict) df_scaled = self.scaler.transform(df) xgb_prob = self.xgb_model.predict_proba(df)[0] mlp_prob = self.mlp_model.predict(df_scaled.reshape(1, -1))[0] # 这里可以融合或分别展示,我选择展示两个模型结果供对比 final_class = int(np.argmax(xgb_prob)) return self.smote_encoder.inverse_transform([final_class])[0]

几个实操要点:

  • 加载模型放在视图外层,避免每次请求都重新加载;在Django中我把它放到apps.py的ready()方法里,或者用全局单例。
  • Keras的HDF5模型文件可能比较大,如果部署到服务器,要注意内存。测试时用load_model('mlp_model.h5')没问题,但生产环境建议转成TensorFlow SavedModel格式。
  • 异常处理:如果前端传了非法数值(比如身高写成了负数),后端要捕获并返回友好提示,不能直接抛500。

4.3 表单校验与用户输入体验

这个项目的数据字段多,如果用户填错了很麻烦。我用了Django Form框架,每个FloatField设置min_value和max_value,对于选择类的字段用ChoiceField,限制可选范围。比如FAF(每周运动频率)范围0-10,TUE(设备使用时间)范围0-24。同时前端加了简单的HTML5校验,但后端校验不能省,因为接口是可以被直接调用的。

4.4 部署层面的小建议

如果只是本地演示,python manage.py runserver 0.0.0.0:8000就够了。但如果要部署到云服务器或者答辩现场演示,最好用gunicorn + nginx。模型文件夹不要提交到Git仓库,用django-environ配置路径。静态文件和数据库都要按Django正式部署的方式收集,避免同学演示时图片加载不出来。


5. 论文写作与答辩现场的加分细节

毕设项目做完之后,论文和答辩是另一场硬仗。这部分不是技术问题,而是“怎么把技术价值讲清楚”的问题。

5.1 论文结构怎么搭

我的论文目录大体是这样:

  1. 绪论:背景、国内外研究现状、研究内容;
  2. 相关技术介绍:决策树、随机森林、深度学习、Django框架;
  3. 数据获取与预处理:数据集来源、清洗、特征工程;
  4. 肥胖预测模型构建:四个模型的原理、参数设置、训练过程;
  5. 模型对比与结果分析:指标评估、混淆矩阵、特征重要性分析;
  6. 系统设计与实现:需求分析、架构设计、功能模块实现;
  7. 总结与展望。

这里有一个常见的误区:不要大篇幅抄算法原理,导师更关心你在项目里怎么用、怎么调、怎么选择。比如第三章写“我为什么保留身高体重而不是直接计算BMI”,第四章写“决策树剪枝前后准确率的变化”,这些才是有效内容。

5.2 常见问题与排查技巧实录

这个项目跑通不难,但调试过程有几个坑值得记录:

  • sklearn版本兼容问题:用joblib保存的模型,如果换了一台电脑且sklearn版本不匹配,加载可能报错。解决办法是固定环境,写requirements.txt并注明版本号。
  • Django加载模型后内存占用高:MLP模型文件大概几百KB,但TensorFlow运行时占了几个GB的内存。如果服务器内存紧张,可以只在预测页面所在进程加载模型,或将Keras模型转为.tflite(不过这会稍微改变预测结果)。
  • 预测结果全部是同一个类别:一般是特征顺序错乱或标准化不对,把训练特征列表打出来逐列核对,看预测分布是否合理。
  • ECharts图表中文乱码:检查后端返回的JSON是否经过ensure_ascii=False,前端html是否设置<meta charset="utf-8">。
  • 表单输入0被当成缺失:Django表单里FloatField(required=False)配合clean_方法要注意,0是合法值,不能当空值过滤掉。
  • 决策树可视化乱码/报错:Graphviz需要本机安装dot程序,不只是pip install graphviz;如果只是展示用,也可以直接用matplotlib画树节点。

5.3 答辩演示的加分操作

答辩时别只对着PPT念,我会建议做一个“现场预测”环节:准备一份典型用户数据,比如“20岁、女性、有家族史、每周运动不到1次、爱吃快餐、饮水少”,当场在系统里输入,展示预测结果为Overweight_Level_I并指出主要成因。这个操作比任何图表都有冲击力,也直观体现了系统的实用价值。

另外,单独准备一张特征重要性排序图,大多是FAF(运动频率)、FCVC(蔬菜频率)、CAEC(餐饮习惯)排前面。答辩时老师问“哪个因素影响最大”,你能直接回答,并解释这和医学常识是吻合的,项目就真正立住了。


最后再说一个实际项目里的小技巧:训练模型时,别只用一个random_state。我一开始固定为42,后面改成2025后结果波动,心态差点崩了。后来学乖了,无论是划分数据集还是模型初始化,都设好随机种子,同时跑几个不同的随机状态,看均值和方差。这样既稳得住实验结果,又能让答辩老师觉得你懂“可复现性”这件事。这个项目的后续还可以继续扩展,比如把年龄、性别分别做分层分析,或者采集真实问卷数据做增量训练,加上权限管理做成多用户系统,发展空间很足。如果你也正在为毕业设计挠头,这个题目真的值得认真做一回。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 9:43:39

Unity项目接入抖音小游戏全流程:构建、转换、适配与性能优化

把Unity项目接到抖音小游戏这件事&#xff0c;我前前后后做了三个项目才敢说摸清了套路。第一次接的时候&#xff0c;我天真地以为Unity导成WebGL再套一层壳就能跑&#xff0c;结果从构建到真机跑通花了整整两天&#xff0c;中间踩的坑包括但不限于包体路径写错、登录回调没接上…

作者头像 李华
网站建设 2026/10/10 9:43:15

链表算法刷题核心技巧:虚拟头节点与双指针实战解析

链表这玩意儿&#xff0c;我在第一次系统性刷算法题的时候&#xff0c;其实是有抵触情绪的。数组它不香吗&#xff1f;随机访问 O(1)&#xff0c;缓存友好&#xff0c;写起来还简单。但真把“代码随想录Day2链表”这个专题完整过了一遍之后&#xff0c;我才意识到&#xff0c;链…

作者头像 李华
网站建设 2026/10/10 9:42:37

TCP三次握手深度解析:从双向确认到序列号同步的设计哲学

上周面了一个候选人&#xff0c;简历上写着五年后端开发。我问他TCP为什么需要三次握手&#xff0c;他几乎不假思索地回答&#xff1a;“因为要确认双方的发送和接收能力都正常。”这个答案对吗&#xff1f;对。能拿分吗&#xff1f;勉强。但你要问我满意吗&#xff0c;老实说&…

作者头像 李华
网站建设 2026/10/10 9:42:13

告别小皮面板:用Docker Compose构建可复现的PHP开发环境

很多刚接触本地开发的朋友&#xff0c;大概都经历过类似的流程&#xff1a;下载一个集成环境软件&#xff0c;双击安装&#xff0c;点开图形面板&#xff0c;一键启动 Nginx 或 Apache 和 MySQL&#xff0c;把网站文件丢进指定目录&#xff0c;浏览器一刷新&#xff0c;好了。这…

作者头像 李华
网站建设 2026/10/10 9:41:46

综合能源微网共享储能主从博弈双层优化:MATLAB完整实现

1. 项目概述与整体思路这几年做综合能源系统优化&#xff0c;大量论文都在用主从博弈&#xff0c;但真正的落地代码细节其实很少公开。这个项目解决的核心问题很直接&#xff1a;综合能源微网&#xff08;电、热、气多能耦合&#xff09;内部有多个利益主体&#xff0c;每个主体…

作者头像 李华
网站建设 2026/10/10 9:41:13

Docker镜像创建实战:Dockerfile写法与构建排坑全指南

说实话&#xff0c;Docker创建镜像这件事&#xff0c;没实操过的人总觉得简单——写个Dockerfile&#xff0c;执行docker build一条命令&#xff0c;顶多等个几分钟。可真到了自己动手&#xff0c;尤其是要交付一个能稳定运行的应用镜像时&#xff0c;各种问题就冒出来了&#…

作者头像 李华