做毕设这么多年带过不少人,我发现在计算机类的题目里,“电商数据分析+销量预测”是最容易出活儿、也最容易翻车的一类。容易出活儿是因为方向明确,谁都知道要做爬虫、要做模型、要做展示;容易翻车是因为很多同学把这几个模块割裂着做,爬虫跑完导出一份CSV,画图脚本单独跑一次,模型训练再看一眼准确率,最后硬拼成一个系统,答辩时一问整体链路就露馅。而“Python电商全维度商品数据分析与随机森林销量预测系统”这个题目,恰好要求你把整条链路从数据采集、清洗、建模,到可视化展示、Web系统集成全部打通,是一个真正能体现工程能力的复合型选题。
这篇文章我会从项目整体拆解开始,把我实际做这套东西时的技术选型思路、关键代码实现、参数调节过程、以及那些文档里不会写的坑,按真实开发的顺序完整过一遍。无论你是拿它当毕业设计,还是想做一个能写进简历的数据分析项目,这条链路都有很强的参考价值。
1. 项目概述与整体设计思路
1.1 核心需求与技术关键词拆解
这个项目标题里的几个关键词不是随便堆的,每拆一个出来都对应着一块具体的技术活:
- “电商全维度商品数据分析”指的是数据维度不能只盯着价格或者销量,至少要覆盖商品标题、价格区间、累计销量、评论数、店铺评分、上架时间、品牌/品类等多个维度。只有维度够全,后续的分析和建模才有深度。
- “随机森林销量预测”是整个项目的模型担当,目标是根据已知的商品特征和销售历史,预测未来一段时间内的销量区间或销量值。
- “Django可视化”是把分析结果和预测结果整合成Web页面,让用户能够在浏览器里交互查看报表和数据图表。
- “爬虫和数据分析”是数据来源与核心处理手段,对应着数据采集和数据预处理两个阶段。
- “大模型”这个标签在毕设里更多是锦上添花,可以把它用在商品评论的文本摘要、推荐理由的自然语言生成上,或者直接作为将来的扩展方向,不作为系统的依赖核心。
有一个很重要的判断:这个项目的核心主线是“数据质量→特征工程→模型效果”,而不是“用什么高级算法”。随机森林之所以是这个题目的优选方案,是因为它对于电商这类表格型数据几乎无需做复杂的特征缩放,对异常值容忍度高,还能输出特征重要性,方便你在答辩时解释“为什么预测结果是这样”。
1.2 技术选型与方案对比
我实际操作下来,技术栈的搭配直接决定了你后期写代码的舒适度:
| 模块 | 推荐方案 | 备选方案 | 选择理由 |
|---|---|---|---|
| 数据采集 | Scrapy + Requests | BeautifulSoup + requests | Scrapy支持并发抓取和断点续爬,数据量大时优势明显 |
| 数据存储 | MySQL | SQLite / CSV | MySQL方便Django ORM直接读取,事务和索引都更成熟 |
| 数据分析 | Pandas + NumPy | 纯Python处理 | Pandas的DataFrame操作是表格型数据分析的标准工具 |
| 模型算法 | scikit-learn随机森林 | XGBoost / LightGBM | 随机森林参数少、调参空间直观,新手也能拿到不错效果 |
| 可视化 | ECharts + pyecharts | Chart.js / Matplotlib | ECharts交互效果好,适合嵌入Django模板展示 |
| Web框架 | Django | Flask + 单独前端 | Django自带ORM、Admin、模板系统,全套功能开箱即用 |
这里我想多说一句为什么不用深度学习做销量预测。电商销量预测本质上是结构化数据的回归/分类问题,表格数据里的特征之间并没有明显的空间或时序关联,深度学习模型在这种场景下不仅训练成本高,而且调参难度大。随机森林作为集成学习中的Bagging代表,通过多棵决策树投票/平均来降低过拟合风险,在几千条到几万条商品数据量级上表现非常稳定。我自己实测下来,在样本量不到2万条时,随机森林的预测效果和XGBoost差距极小,但代码量和对新手友好程度高出一大截。
1.3 系统整体架构与数据流向
整个系统的架构从数据流的角度看非常清晰,我也建议你按这个顺序去搭建代码,而不是按功能模块并行开发:
- 爬虫模块抓取电商商品数据,写入MySQL商品主表。
- 数据清洗脚本对缺失值、重复值、异常值做处理,生成分析宽表。
- 特征工程脚本从宽表中构造销量预测所需的特征集和标签列。
- 模型训练脚本输出随机森林模型文件(.pkl或.joblib),同时输出特征重要性分析结果。
- Django应用读取MySQL中的数据,页面通过ECharts展示多维分析图表和预测结果。
- 预测功能通过调用训练好的模型文件,对用户选择的商品特征实时预测销量。
这个架构最大的好处是每个环节的产物都是独立的:数据是数据、模型是模型、Web是Web。如果某个环节出问题(比如爬虫被封IP),不需要动到其他模块,替换数据源重新跑一遍清洗和训练就行。我在实际做的时候,刻意把爬虫输出和模型训练通过数据库解耦开,后期换数据源、加数据维度都是直接改配置,基本不动核心代码。
2. 系统环境搭建与项目初始化
2.1 开发环境与依赖清单
这个项目的环境搭建并不复杂,但有几处细节必须提前处理好,不然后面会反复折腾。
我推荐使用Python 3.9或3.10版本。太老的版本对Django 4.x的高版本支持不好,太新的3.12在某些依赖库上可能出现源码编译问题(尤其是Windows下安装scikit-learn或pandas时)。用conda创建独立环境最省心:
conda create -n ecommerce python=3.10 conda activate ecommerce核心依赖清单如下:
pip install django==4.2 pip install scikit-learn==1.3.2 pip install pandas==2.0.3 pip install numpy==1.24.3 pip install scrapy==2.11 pip install pymysql pip install pyecharts==2.0.5 pip install matplotlib==3.7.2 pip install joblib这里有个版本坑值得提前说明:pyecharts 2.x和Django模板的兼容性比1.x更好,但2.x的API变化较大,网上的旧教程大多是基于1.x写的,如果你看到类似pyecharts.charts import Bar的写法,实际上2.x已经是这样了,而pyecharts.Chart这种写法是1.x的,不要混着用。
2.2 Django项目结构规划
Django项目我建议按下面的目录结构来组织,这种结构把“数据分析”和“Web展示”清晰地分开,答辩时讲起来也顺:
ecommerce_system/ ├── manage.py ├── data_analysis/ # 数据分析与建模模块 │ ├── crawler/ # 爬虫代码 │ ├── preprocessing/ # 数据清洗与特征工程 │ ├── model_training/ # 模型训练与评估脚本 │ └── output/ # 模型文件与结果图表输出 ├── goods_analysis/ # Django主应用 │ ├── views.py # 视图函数 │ ├── urls.py # 路由配置 │ ├── models.py # ORM模型 │ └── templates/ # 前端模板 │ └── index.html └── db.sqlite3 / mysql配置一个容易忽略的点是:Django的models是给Web系统查询展示数据用的,它不一定需要覆盖原始数据的全部字段。我在实际项目里只把分析结果、统计聚合表、预测记录这三类数据纳入Django的ORM管理,原始商品明细仍然放在MySQL的独立表里,两者通过商品ID关联。这样做的好处是Web层轻量、查询快,而且数据分析和Web开发可以并行推进。
2.3 数据库设计与关键表结构
数据库表设计是整个系统的基础,设计得好后期能省很多事。核心表我分成了三张:
- 商品明细表:存储爬虫采集的原始商品信息,主要字段包括商品id、标题、类目、品牌、价格、累计评论数、销量、店铺名、店铺评分、上架时间、采集时间等。
- 特征宽表:存储清洗和特征工程后的建模数据,包含价格区间编码、评论数区间、店铺评分、是否自营、类目编码、目标销量等。
- 预测记录表:存储用户在网页端提交预测请求时生成的结果记录,字段包括用户输入的特征快照、预测结果、预测时间。
这里要强调一个设计原则:特征宽表不要和原始明细表混在一起。原始表的数据是“脏”的,哪怕你清洗过,也尽量不要动它,因为你后续随时可能需要回溯排查数据问题。特征宽表是从原始表处理得到的建模专用数据,它可以随时用清洗脚本重建,保证可复现性。我自己在初期图省事,直接在原始表上加了特征列,结果清洗脚本跑两次字段就乱套了,后来才拆开重做。
3. 数据采集与预处理实战
3.1 爬虫模块的实现要点与合规注意事项
爬虫是这个项目的数据源头。我在实现时用的是Scrapy框架,针对某电商平台公开的商品搜索页进行抓取。核心逻辑是:
- 构造搜索请求URL,带上关键词和分页参数。
- 解析返回的HTML或JSON接口,提取商品标题、价格、评论数、店铺信息等字段。
- 数据存入MySQL,同时去重和增量更新。
下面是一个简化版的Item定义和爬虫示例,实际字段按你的需求扩展:
import scrapy class GoodsItem(scrapy.Item): goods_id = scrapy.Field() title = scrapy.Field() price = scrapy.Field() comment_count = scrapy.Field() shop_name = scrapy.Field() shop_score = scrapy.Field() category = scrapy.Field() url = scrapy.Field()爬虫写起来不难,难的是稳定抓取和目标平台的限制。这里分享几个我实测有效的经验:
- 请求频率必须控制,建议每个请求间隔1秒以上,并发数控制在2-4之间。千万不要为了追求速度开高并发,一单IP被限制,整个采集进程都会中断。
- User-Agent和Cookie要模拟真实浏览器。只改UA还不够,部分平台还会校验请求头顺序和TLS指纹,如果你发现返回的数据字段明显缺失,先检查是不是被识别成了爬虫。
- 优先找页面里的JSON接口,而不是解析HTML。电商平台的前端页面大多由异步接口渲染,直接解析HTML不仅速度慢,而且字段结构容易变。用浏览器的开发者工具抓包,找到返回JSON数据的XHR接口,解析效率和稳定性都高很多。
必须提醒一点:爬虫的使用要严格遵守目标平台的robots协议和服务条款,只采集公开可见的信息,控制合理频率,不得用于任何商业用途或对目标平台造成压力。毕设项目里强调数据获取的合规性,在答辩时也是加分项,因为老师们其实很关注这一点。
3.2 数据清洗的完整流程与关键操作
爬下来的数据没法直接用,这是所有数据分析人都懂的道理。我实际工作中最大的体会是:清洗脚本的核心不是“怎么写”,而是“每一步为什么这么做”。
我的清洗流程分四步:
第一步是去重。同一商品可能被多个关键词的搜索结果重复抓取,我以商品id为主键做去重,保留采集时间最新的那条记录。这一步比较简单,SQL里加个DISTINCT或者Pandas里drop_duplicates就行。
第二步是缺失值处理。我在处理商品价格和评论数时发现,缺失率最高的往往是最新款或预售款商品,它们可能没有评论数。对于缺失值,我采用的策略是:价格缺失直接删除(没有价格的数据无法用于价格区间分析),评论数缺失用该类目评论数的中位数填充,店铺评分缺失用全类目均值填充。用中位数而不是均值的原因是评论数分布极度右偏,均值会被爆款商品拉高,填充后会产生偏差。
第三步是异常值处理。电商数据里有两种常见异常:一种是价格异常,比如某个商品价格标为0.01元,这通常是凑单链接或测试商品;另一种是销量异常,比如一个链接同时刷了数千条评论,评论数远高于正常水平。我的处理方式是定义一个合理区间,超出区间上下限5倍的点直接剔除或者缩尾到边界值。实际操作里用Pandas的quantile方法很容易实现:
import pandas as pd df = pd.read_sql('SELECT * FROM goods_detail', engine) # 价格异常处理:剔除小于1元和大于类目95分位数的记录 for cat in df['category'].unique(): subset = df[df['category'] == cat] low, high = subset['price'].quantile([0.01, 0.95]) df.loc[(df['category'] == cat) & (df['price'] < low), 'price'] = low df.loc[(df['category'] == cat) & (df['price'] > high), 'price'] = high第四步是标准化。这一步需要把原始字段转为模型可用的数字特征,我会在特征工程部分详述。
3.3 特征工程:从一个表到能用模型的宽表
特征工程是整个项目里对预测效果影响最大的一步,也是很多空有代码没有效果的项目最大的短板。我在这个项目里构造了以下几类特征:
- 价格类特征:原始价格、价格/类目均价的比例、价格分位数区间编码。
- 评论类特征:评论数、评论数/销量的比值、评论数的对数变换。
- 店铺类特征:店铺评分、店铺评分与类目均值的差值。
- 商品类特征:标题长度、是否包含“旗舰店”“热卖”等词、类目one-hot编码。
- 时间类特征:上架距今天数、上架月份、是否在双11/618等大促周期内。
为什么要做这么多特征?因为随机森林虽然能处理非线性关系,但它本质上是通过特征划分来学习的,如果特征本身区分度不够,再多的树也没用。举个例子:直接用价格预测销量,效果通常很差,因为价格对不同类目的商品意义完全不同;但当你把价格转换成“价格/类目均价比”这个相对特征后,不同类目的商品就在同一个尺度上可比了,这个特征的预测贡献明显提升。
我建议你在建模前先用Pandas的corr()方法看看各个特征与销量之间的相关性,把相关系数几乎为0的特征剔除掉,这一步既能让模型更简洁,也能让你在答辩时展示自己“有特征筛选意识”。
4. 随机森林销量预测模型构建
4.1 问题定义与评价指标选择
在做模型之前,先要把问题定义清楚。销量预测既可以做回归(预测具体销量数值)也可以做分类(预测销量区间)。我在实际做的过程中,最终选择了回归方案,因为分类需要手动切分销量区间,区间边界的选择会影响结果的可解释性,回归则直接给出预测数值,便于直接和真实值对比。
回归问题的核心评估指标是决定系数R²和均方根误差RMSE。R²代表模型解释了数据中多少比例的方差,数值越大越好;RMSE代表预测值和真实值之间的平均偏差,数值越小越好。我当时定下的目标是R²不低于0.7,RMSE控制在真实销量标准差的30%以内。为什么这么定?因为电商销量数据本身的波动极大,真要达到R²=0.9以上,需要非常丰富的时序信息和竞争信息,这在毕设项目里不太现实。明确合理的指标预期,避免后期为了追求数字好看而过度调参,这是我想提醒所有做这个方向的人的一件事。
4.2 数据集划分与训练流程
数据划分上,我用的是时间序列切分而非随机切分。这是很多人容易忽略的:销量预测的场景下,训练集和测试集如果随机打乱,模型会用“未来的数据”预测“过去的数据”,评估结果虚高,但在真实应用里会翻车。正确做法是按时间切分,取前80%时间范围内的数据作为训练集,后20%作为测试集。
from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split from sklearn.metrics import r2_score, mean_squared_error import pandas as pd import joblib features = ['price_ratio', 'comment_log', 'shop_score_diff', 'days_since_online', 'title_length', 'promotion_flag'] X = df[features] y = df['sales_volume'] # 按时间排序后切分 df = df.sort_values('online_days') split_idx = int(len(df) * 0.8) X_train, X_test = X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test = y.iloc[:split_idx], y.iloc[split_idx:] model = RandomForestRegressor( n_estimators=300, max_depth=20, min_samples_leaf=3, random_state=42 ) model.fit(X_train, y_train) y_pred = model.predict(X_test) print('R2:', r2_score(y_test, y_pred)) print('RMSE:', mean_squared_error(y_test, y_pred, squared=False)) joblib.dump(model, 'data_analysis/output/sales_model.pkl')这里的参数是我经过一轮初调后确定的。n_estimators设为300,因为基学习器太少模型不稳,太多训练时间不成比例增长;max_depth设为20,让树有一定深度来捕捉特征交互,但不至于完全展开过拟合;min_samples_leaf设为3,相当于要求每个叶子节点至少3个样本才能继续分裂,这个参数是抑制过拟合最有效的杠杆。
4.3 超参数调优与特征重要性分析
调参方面,我没有用网格搜索全量跑,因为组合空间太大,耗时太长。我采用的是“先粗后细”的两轮策略:
第一轮先固定n_estimators=200,粗调max_depth在5、10、15、20、30中选一个,用交叉验证观察R²的变化趋势。第二轮在选定max_depth的基础上,调节min_samples_leaf在1、2、3、5中的取值。这样两轮跑完,基本能找到稳定区间,而且每轮10分钟以内能出结果,比GridSearchCV动辄几小时的体验好太多。
训练完成后一定要看特征重要性。随机森林自带feature_importances_属性,直接输出各特征对预测的贡献占比。我跑出来的结果中,评论数对数、价格占比和促销标志这三个特征贡献了大部分重要性,这说明销量主要由商品的受欢迎程度、价格竞争力和促销力度驱动。这个结论本身就有分析价值,在系统的“特征分析”页面里展示特征重要性柱状图,答辩时老师问“为什么选这些特征”,你可以直接拿这张图说话。
需要注意的是:特征重要性是相对值,不是绝对值。它告诉你的是“在这个模型里,哪个特征贡献大”,而不是“哪个特征客观上更重要”。如果两个特征高度相关,模型会把重要性分散到两者之间,这是Bagging类模型的正常现象,不必过于纠结。
5. 可视化报表与Django系统集成
5.1 可视化方案选型与图表设计
可视化是这个项目的门面,也是用户感知最强的部分。我选ECharts为核心解决方案,原因很简单:交互功能内置,缩放、提示框、切换数据系列都不需要自己写JS事件;中文本地化做得好;导出图片方便,答辩做PPT可以直接用系统截图。
图表的设计要围绕“全维度分析”这个题眼展开,我当时一共做了6类核心图表:
- 类目销量分布柱状图:展示不同商品类目的销量总和排名,一眼看出主营品类。
- 价格区间与销量关系散点图:横轴价格、纵轴销量、点大小代表评论数,展示价格与销量的相关性。
- 评论数与销量对应关系图:用气泡图展示评论量级与销量水平的关系。
- 商品标题词频柱状图:统计标题中的高频词,帮助理解用户搜索偏好。
- 店铺评分分布箱线图:展示主流店铺评分的集中区间和异常店铺分布。
- 特征重要性排序图:展示随机森林模型中各特征的贡献占比。
这6类图表基本覆盖了“描述性分析”的全部模块,配合预测功能形成了完整的闭环。
5.2 Django视图与ECharts集成实现
集成的技术路线其实不复杂:Django视图从数据库读取聚合数据,打包成JSON传给模板,前端用ECharts渲染。关键是把数据查询逻辑写清楚,不要在前端做复杂计算。
# views.py 部分示例 from django.shortcuts import render from .models import CategoryStat def index(request): # 类目销量聚合数据 category_data = ( CategoryStat.objects.values('category') .annotate(total_sales=Sum('sales_volume')) .order_by('-total_sales')[:10] ) categories = [item['category'] for item in category_data] sales = [item['total_sales'] for item in category_data] context = { 'categories': categories, 'sales': sales, } return render(request, 'index.html', context)前端模板里,把数据塞进ECharts的配置项:
var chart = echarts.init(document.getElementById('chart1')); chart.setOption({ title: { text: '类目销量TOP10' }, xAxis: { type: 'category', data: {{ categories|safe }} }, yAxis: { type: 'value' }, series: [{ type: 'bar', data: {{ sales|safe }}, itemStyle: { color: '#5470c6' } }] });这里有个Django模板的坑我第一次踩到时很不解:把列表变量直接传给ECharts的data数组时,需要用|safe过滤器,否则Django模板系统会把方括号转义成HTML实体,图表只显示空白。数据量不大时,也可以直接在视图里用json.dumps序列化好再传入。
5.3 销量预测功能的前后端联调
预测功能的实现逻辑是:用户在前端页面选择或输入商品特征,表单提交后,Django视图读取请求参数,经过和训练时完全相同的特征转换,调用模型文件执行预测,返回结果并存储到预测记录表。
特征转换的一致性特别重要,这是实战中最容易踩的雷。训练时你用的是“评论数对数”这个特征,预测时用户输入的是原始评论数,如果忘记做同样的对数变换,模型输入分布就会和训练时不一致,预测结果必然失真。我的解决方法是把特征转换逻辑抽成一个独立的函数,训练和预测共用:
def build_model_features(raw_data): return [ raw_data['price'] / category_mean_price[raw_data['category']], np.log1p(raw_data['comment_count']), raw_data['shop_score'] - category_mean_score[raw_data['category']], (date.today() - raw_data['online_date']).days, len(raw_data['title']), is_promotion(raw_data['online_date']) ]这个函数是“一处定义、两处使用”的典型做法,训练脚本和Django的视图函数都import它,从根源上避免了前后逻辑不一致的问题。我见过不少项目在训练脚本里用一套特征变换,在Web预测里用另一套甚至完全不做变换,最后预测结果一塌糊涂,基本可以断定就是这类问题导致的。
5.4 页面布局与交互体验优化
页面布局我采用典型的数据大屏风格:顶部标题栏,左侧放类目分析和价格分析两个图表,右侧放评论分析和店铺评分两个图表,中间主区域放销量预测模块。这种布局在答辩演示时很占便宜,因为导师一眼就能看到项目的核心能力,不用滚动页面找功能。
交互上,我做了两个细节:一是图表tab切换,让用户可以在“分析报表”和“预测功能”之间快速切换;二是预测表单增加了“常见商品特征模板”下拉框,用户选择“手机类目”等模板后自动填充典型参数,一键出预测结果。这两个小改动不复杂,但对整体作品完成度的提升非常明显。答辩时很多同学点开页面后不知道先干什么,有交互引导就好很多。
6. 常见问题与排查技巧
6.1 环境与依赖相关的典型报错
这个项目环境问题占了后端问题的很大比例。我把最常见的几类整理出来:
一是pandas和numpy版本兼容问题。如果安装时提示找不到numpy.core.multiarray,多半是版本不匹配,我用的是pandas 2.0.3配numpy 1.24.3,这个组合经过验证是稳定的。还有新版本numpy合并C扩展后,某些旧版pandas在Windows上会报module compiled错误,解决方案就是像我上面那样锁定版本安装。
二是pyecharts导入报错。pyecharts 2.x把底层渲染改成了单独包,如果遇到pyecharts.render导入失败,检查一下是否安装了simplejson和jinja2,这两个是它的间接依赖。另外2.x版本中图表类的路径大多在pyecharts.charts下,不要照抄1.x教程里的写法。
三是MySQL连接问题。Django连接MySQL默认需要mysqlclient,但在Windows上编译这个包经常失败。我的替代方案是用pymysql,然后在项目__init__.py里加上:
import pymysql pymysql.install_as_MySQLdb()这样Django的ORM就能正常使用MySQL了。这个操作只影响启动时的数据库驱动加载逻辑,不影响其他功能。
6.2 爬虫与数据质量相关的坑
爬虫方面最常见的坑就是抓取频率过高导致IP被限制。我一开始贪快,设置了并发8、延迟0.5秒,跑了半小时之后请求开始大量失败。后来我把延迟调到1.5秒、并发降到3,稳定运行了两个小时都没问题。数据采集本来就是细水长流的活,尤其是毕设数据量要求不高,几千条有效数据完全够用,没必要追求速度。
另外一个隐蔽的坑是编码问题。电商平台的搜索接口返回的数据偶尔会有繁体字、表情符号或特殊字符,直接写入MySQL可能在utf8编码下报错。我的处理方案是写入时统一转为utf8mb4编码,Python侧读取时用errors='ignore'容错:
import pymysql conn = pymysql.connect(host='localhost', user='root', password='123456', charset='utf8mb4', database='ecommerce')同时,在清洗阶段把文本字段里的非中英文字符统一剔除,确保后续分析字段的干净度。
6.3 模型效果不达预期的排查路径
模型R²偏低是很多同学会来找我咨询的问题。根据我的排查经验,按优先级从上到下检查:
第一条路径是数据质量。先查训练数据里是否混入了大量异常值或缺失值填充不当的记录,尤其是评论数为0但销量极高的商品,这种记录会严重干扰模型。我遇到过评论数为0、价格9.9元的商品月销8000多的特例,最初模型总是预测偏低,后来定位到是这类极端样本挤压了正常样本的空间。
第二条路径是特征完备性。如果只有价格和评论数两个特征,模型效果上限一定不高。至少要补充店铺评分、上架时长、促销标志这几个基本维度,再往后可以加类目编码和标题文本特征。特征维度从5个加到10个之后,R²明显提升了一个档次。
第三条路径是参数过拟合或欠拟合。如果你发现训练集R²很高但测试集很低,说明过拟合了,把max_depth调小或把min_samples_leaf调大;如果两边都低,说明模型太弱或特征太少,优先加特征而不是加树的数量。
6.4 答辩演示时容易翻车的环节
答辩演示环节,我见过最多的翻车现场就是预测模块没有预置数据,学生现场手动输入参数,又正好输入了一个特征分布边缘的样本,模型给出了一个看起来很离谱的预测值。我的经验是:提前准备3个典型商品的复合特征作为预设模板;演示时先点“手机类目模板”说明预测流程,再手动改一个参数展示结果变化。这样既展示了功能,又控制了输入范围。
还有一个翻车点是图表加载缓慢。Django页面同时加载6张ECharts图表时,如果每个图表的数据量过大,首屏加载会非常卡顿。我的做法是每张图表的后端接口只返回TOP20的聚合数据,或者在前端用dataZoom组件限制初始展示范围,保证页面在2秒内能完整渲染。答辩时电脑性能不可控,页面加载越轻越不容易出问题。
写在最后
从环境搭建到爬虫采集、数据清洗、特征工程、模型训练,再到Django集成和可视化展示,这一整套流程走下来,我最大的感受是:这个项目真正考验的不是某一个算法有多深,而是你对整条数据处理链路的理解和工程实现能力。随机森林模型本身只是一个工具,让这个项目出彩的,是数据清洗时的细致程度、特征构造时的领域理解,以及把分析结果用可视化和Web形式呈现出来的表达能力。即使在答辩时被问到“为什么不用深度学习”,你也能有理有据地告诉老师:在这个数据规模和业务场景下,随机森林在效果、可解释性和工程复杂度之间取得了最好的平衡。
如果后续你想继续扩展这个项目,可以从两个方向入手:一是接入大模型能力,对商品标题做自动摘要或对评论做情感分析,输出更丰富的文本维度特征;二是引入商品销量时序数据,改用Prophet或时序Transformer做短期销量预测,和当前的特征化随机森林形成对比。那样的话,这个项目就不仅仅是一个毕设,而是可以真正作为数据分析完整案例写进作品集的东西了。