
做毕设选题目的时候很多人第一反应是往热门里扎目标检测、推荐系统、大模型微调……但真正动手之后才发现要么数据量撑不起模型要么业务背景讲不清楚最后论文写得像说明书。我做的这个项目选的是基于机器学习的日化产品销量影响因素的分析与预测方向不算花哨但做完之后收获非常大——数据量足够、业务逻辑清晰、算法有对比空间而且源码和论文的完整性都很好。这篇就把它当成一个完整的毕设/项目复盘来写从头到尾讲清楚我是怎么拆解题目、处理数据、构造特征、训练模型到最终把论文和系统串起来的。如果你也在纠结销量预测类的题目怎么落地或者手上正好有一堆零售数据不知道怎么挖出价值这篇应该能给你一条可以直接参考的路线。1. 为什么日化产品是销量预测类毕设的最优解先说选题。导师一开始给我的方向是零售数据挖掘范围很大等于什么都没说。我自己把候选品类列了一遍生鲜、零食、日化、服饰、数码。逐个筛下来日化产品赢在几个硬指标上。1.1 数据频率够高模型才有得学日化品类洗发水、沐浴露、洗衣液、纸巾、牙膏这一类属于高频消耗品复购周期短。我做的是一个模拟某连锁便利店的日化货架销售数据覆盖了近三年的日度销量记录。跟服饰、数码这类低频耐用品比起来日化品的日销量序列几乎是连续的很少出现大量零值日期。这非常重要——如果一个商品一整月才卖几单你拿什么去预测明天的销量模型学到的全是噪声。日化品正好避开了这个坑日均销量稳定季节性波动明显适合做时序类或者回归类的建模。1.2 SKU多影响因素自然丰富同一个品类下面光是洗发水就有去屑、柔顺、控油、男士、家庭装等多种功能定位价格从十几块到七八十块不等。SKU多意味着样本量被撑起来了而且不同价位、不同定位的商品对促销和价格的反应差异很大这恰恰是影响因素分析想要的东西。我在数据处理阶段统计了一下筛选出的可建模SKU一共有180多个每个SKU都带了日常售价、促销价、促销状态、陈列位置、所在门店等级这些业务字段。有差异就有对比有对比就能写分析论文的影响因素部分就有着落了。1.3 业务变化有迹可循解释起来不费劲日化产品的销量波动是有明确业务原因的大促、节假日、季节交替、天气突变。比如夏天驱蚊液和花露水销量暴涨冬天护手霜和滋润型沐浴露走强再比如满199减100这种大促前一周销量被压制、大促当天爆量、大促后几天回落的虹吸效应都是能直接观察到的真实现象。这意味着什么意味着你做的每一个特征、模型给出来的每一个重要性排序都可以落到业务逻辑上。答辩的时候导师最爱问的这个结果为什么合理——你能讲出故事来这比单纯展示AUC和F1分数有说服力得多。1.4 算法空间大传统机器学习到深度学习都能放进去我们这个项目的标题里同时出现了机器学习和深度学习算法这其实是毕设里很典型的靠内容撑题目写法。我的方案是用线性回归做baseline用LightGBM和XGBoost做树模型主力再用LSTM做深度学习路线。三组模型对比着写既有核心实现又有调参过程论文的实验对比章节自然就厚起来了。一句话总结选型逻辑日化品销量做预测本质上是回归问题 时序问题 可解释性要求的复合体任何一个单模型都能做但没有一个单模型能同时把这三件事讲到极致。所以最好的策略不是选一个模型而是选一批有代表性的模型做对比让算法的差异本身成为论文的看点。2. 数据预处理这步偷懒后面全是坑很多人拿到数据之后第一件事就是敲df.head()然后急着上手建模。我劝你冷静。日化产品的零售数据是所有行业数据里最脏的一类不认真处理后面所有模型结果都是虚的。2.1 商品名称归一的空难同一个商品在不同门店、不同批次里的名称五花八门。举例来说某品牌洗发水柔顺型400ml可能在另一家店叫某品牌洗发水(柔顺)400ml还有可能把400ml写在前面。如果你不做归一化这些数据在模型眼里就是两个完全不同的商品后果就是特征稀疏、样本被割裂销量预测值忽高忽低。我的做法是两步走先做硬匹配完全相同的主品牌和规格再做规则匹配提取品牌词、功能词、规格数值。规则匹配当时花了好几天用正则把商品名拆成结构化字段品牌、品类、功能定位、规格ml、包装类型。做完之后180多个可建模的SKU才稳定下来。这类工作没有技术上的惊天动地但它是后面一切分析的地基。2.2 促销价与成交价的二义性零售数据里经常同时存在日常售价和促销价。这两个字段直接预测模型容易出问题模型会发现促销价越低销量越高但这个规律到底是真实的因果还是字段本身就看错日期我在原始数据里发现过一个典型的坑部分记录中促销价字段填的其实是促销活动开始前一天的日常价等到活动真正开始那天促销价反而没有更新。如果你直接拿这个字段建模模型会认为价格没变但销量暴涨然后拼命用节假日特征来拟合这个异常值。所以我把价格字段清洗成了实际成交价格——也就是当日真实出库单价缺了就用日常售价补促销标志位才真正用上。2.3 缺货造成的销量零值日化产品也有缺货的时候但我发现很多SKU的零销量不是没人买是库里没货。如果不区分这两者模型就会学到一个错误的信号节假日反而销量为零。我的处理方式很简单找到目标SKU如果某天销量为零且库存也为零就把这天标记成缺货日预测时直接跳过这个样本不参与训练和评估。这样做表面上是丢了一部分数据实际上让模型的训练集干净非常多。2.4 防止数据泄露的切分方式这是整个项目里最重要的一个分水岭。销量预测本质上是时间序列任务如果用随机切分把数据分成训练集和测试集模型就会通过看到未来的数据来作弊。比如你在8月训练时用了9月的标签到了9月的预测环节模型只是把答案背了出来指标自然好看但毫无意义。我采用的切分方式是按时间顺序切分前70%做训练集中间15%做验证集最后15%做测试集。为了保证测试集能覆盖到不同季节我特意把时间窗口放到一个完整自然年以上。具体实现上我用的是一个自定义的TimeSeriesSplit类每次只允许模型用过去的窗口预测未来的窗口从源头杜绝了数据泄露。这个问题我建议你在论文里单独拿出来写一节属于答辩老师特别看重的那类方法论细节。3. 特征工程把影响因素变成模型能看懂的数值题目里影响因素分析这几个字才是核心命题。模型怎么知道大促会影响销量季节怎么进模型这不靠算法自己悟全靠特征工程。我这边把特征分成了六个维度每个维度都在最后的影响因素分析阶段派上了用场。3.1 基础时间特征星期几、是否周末、月份、季度、当月的第几天。日化品的周期性强每个月的月初和月中发薪日附近销量会有一个小尖峰周末的家庭采购型消费也更旺盛。这些特征虽然不起眼但它是树模型天然的强特征。我额外做了一组节假日前中后特征节前第几天、节后第几天、是否法定节假日当天。单独用是否节假日0/1这种标签太粗暴了因为大促对销量的拉升是有过程感的——节前三天就开始囤货节中回落节后进入淡季。用一个距离变量表达这种过程比一个二分类标签信息量大得多。3.2 促销与价格特征促销价、日常售价、折扣率、促销持续时间、是否跨品类满减、促销级别单品直降/满减/买赠。折扣率是一个特别好的特征因为它直接把降价力度量化了。满减类活动对销量的影响明显强于单品直降但模型自己不知道所以我把促销类型也编码进去。需要注意折扣率的计算不是简单用促销价除以日常价还要考虑满减的门槛。比如满199减100对单价十几块钱的牙膏来说用户需要囤十几支才能享受优惠这时折合到单品的实际折扣远低于表面上的折扣。我当时把满减按可达成门槛的组合做了一个预估折扣率虽然不精确但比直接用标价靠谱多了。3.3 历史销量滑窗特征这是时间序列预测的核心。滞后期是销量、前7天平均销量、前14天平均销量、前28天平均销量、同品类的整体销量均值、销量环比变化率。这些特征做出来之后LightGBM的训练精度立刻上升了一个台阶Feature Importance排名前五的基本都是滑窗特征。这里有一个很多人会犯的错误滑窗特征里包含了未来信息。比如你用t时刻的数据预测t1但滑窗特征是计算到t7天之后的那这个特征本身就等于给了模型一个答案的提示。我的规避方法是保证每个样本的特征窗口只包含样本时刻之前的数据且验证集和测试集上的特征全部来自历史数据绝不用未来信息回填。3.4 天气与季节特征日化品和天气的关系被很多人忽视但它非常有意思。我拿到的数据里有一份模拟气象表包含最高温、最低温、降雨量、湿度、风力。把天气数据按门店城市去关联之后发现了几个明显的规律降雨量大的日子线下门店的日化品销量普遍下降10%~20%气温超过30度时洗护类销量明显上升湿度大的季节除湿袋、芳香剂这类商品的销量几乎翻倍。这类特征在模型里可能排不到前列但它在影响因素分析章节里确实是不可少的。你可以画一个散点图或者分组箱线图把天气和销量的关系可视化成论文里的插图直观又有说服力。3.5 门店与陈列特征门店等级、货架位置、陈列面数、是否放在收银台附近。虽然这些特征在预测阶段的增益不显著但在分析哪些因素影响最大的时候它们是重要的控制变量。比如某品牌纸巾在A类门店销量远超B类门店可能不是消费者偏好问题而是A类门店给它安排了端架陈列曝光量大。3.6 同品类联动特征同类目商品的总销量、同品牌其他SKU的销量、竞品销量占比。日化品的货架份额是零和博弈一个品牌的新品上市往往吃掉的是另一个品牌的份额。把这个逻辑用同品类其他商品销量这个特征表达出来模型会学得非常快。整个特征工程做完我共构造了63个维度特征。在论文里我把这些特征整理成了一张表每一列标出特征含义、类型、来源字段和处理方法。答辩时老师拿到这张表基本就不再追问你做了哪些特征了。4. 算法模型与训练细节从baseline到LSTM这套项目我最终实现了三组主力模型外加一组集成融合。每个模型承担的定位不一样训练细节和坑也不太一样。4.1 线性回归做差值不做上限很多人觉得线性回归放在毕设里太没技术含量但它是最好的baseline能帮你快速确认特征管道是不是通的。我用岭回归做了一版把所有数值特征做标准化之后跑了一遍测试集RMSE大概在17.6左右单位件/天R方约0.58。这个成绩就是全项目的下限。注意线性回归不适合直接用销量作为目标变量因为销量是右偏分布直接拟合会让高销量SKU主导误差。我做了个log1p变换把目标拉成近似正态效果立杆见影。记录一下变换后的RMSE降低约12%但要对预测结果做expm1回变换。4.2 LightGBM与XGBoost树模型是日化数据的实战之王这两兄弟放在一起说因为核心思路一样用一堆弱决策树做集成在前面的特征工程基础上暴力拟合。实际操作中LightGBM表现比XGBoost略好主要原因是LightGBM对类别特征的天然支持更好门店等级、促销类型这种高基数类别字段不需要单独做独热编码就能直接喂进去。训练配置上我调了几个关键参数n_estimators: 2000配合早停learning_rate: 0.03目的是给足叶子数避免过拟合num_leaves: 31经验值往大了调训练集精度会提升但测试集容易崩feature_fraction: 0.8相当于每次随机砍掉20%的特征提高泛化能力early_stopping_rounds: 50用验证集做早停这个设置直接避免了我手动判断到底训多少轮注意一个时间序列场景下的细节交叉验证不能随便用普通的KFold要用带时序顺序切分的验证方式否则模型会被未来数据剧透。LightGBM的训练速度很快180个SKU全量训练大概也就两三分钟一轮这个体量做毕设刚刚好——既不会因为跑不动而卡住也不至于因为速度太快没有调参的体验感。最终LightGBM在测试集上的RMSE到了9.8R方到了0.87XGBoost略差一点但差距很小。这个精度说明什么说明日化品销量的可解释性方差很大促销、节假日、价格这些因素确实主导了销量的起伏。后面到了影响因素分析阶段可以很有底气地讲故事。4.3 LSTM深度学习路线的关键实现LSTM是标题里深度学习算法这几个字的主要承担者。我一开始也想用Transformer或者TCN但仔细评估之后觉得LSTM更合适样本量在几万级别LSTM是最不容易过拟合的时序模型而且训练资源要求低答辩讲起来也经典。数据构造上我把单个SKU当做一个独立的时间序列构造长度为14天的滑窗输入目标是预测第15天的销量。做了一组min-max归一化注意这个归一化必须是用训练集的min和max去缩放验证集和测试集否则又会踩数据泄露的坑。网络结构搭了三层LSTM加一层Dense核心代码结构大致是model Sequential([ LSTM(64, return_sequencesTrue, input_shape(14, feature_dim)), Dropout(0.2), LSTM(32, return_sequencesFalse), Dropout(0.2), Dense(16, activationrelu), Dense(1) ]) model.compile(optimizeradam, lossmse, metrics[mae])这里的feature_dim是28因为我把每个SKU的48维特征在滑窗里做了降维压缩只保留最重要的价格、促销、节假日、历史销量等字段。LSTM的训练比较慢我做了早停大概在第80轮左右收敛测试集RMSE在11.5左右比LightGBM差一些但意外地在某个促销剧烈波动的子集上LSTM的预测更稳——树模型对未见过的促销形式容易外推过度LSTM反而因为记忆了序列模式而表现更理性。4.4 融合模型的收益最后我把LightGBM和LSTM做了简单加权融合权重是0.7和0.3RMSE从9.8降到了9.2。虽然提升不大但这是个很好的论文素材——你可以写单一模型在局部场景各有优势融合可以取长补短这也是业界在销量预测场景比较成熟的做法。融合模型的实现不要太花哨我试过Stacking、线性回归套嵌效果和时间成本不成比例最后还是用固定的权重简单高效。答辩的时候讲为什么用固定权重而不是可学习的Stacking——因为样本量有限可学习权重容易过拟合固定权重在验证集上反而是最优的。5. 影响因素量化分析让模型开口说话模型训练完成不算完论文真正要让老师觉得有价值的是影响因素分析。树模型给了Feature Importance但Feature Importance只说哪个特征重要没说重要特征是怎么影响销量的。这一步我用SHAP值来做。5.1 特征重要性的排序结果从LightGBM的Feature Importance和SHAP值两边看排在前十的影响因素里集中在三个大类上促销相关特征促销标志、折扣率、满减类型、时间相关特征节假日、星期、月份、历史销量滑窗特征。这三类加起来占了整体重要性的八成以上。价格特征反而排得靠后这个结果让我有点意外但后来想通了日化品的价格弹性没有快消食品那么强消费者对洗发水的价格敏感度远低于对零食的敏感度真正拉动销量的是有没有活动而不是贵不贵几块钱。5.2 SHAP值告诉我们方向和幅度SHAP不只是排名它能给每个特征在每个样本上的影响方向和大小。我把所有样本的SHAP值做了汇总得出了几个可写进论文的关键结论第一促销标志位为正贡献但存在边际递减。当折扣力度从8折变成6折时销量平均拉升约35%但从6折变成4折时拉升幅度只有十几个百分点。为什么会这样因为日化品的囤货属性决定了消费者的库存容量有限便宜到一定程度后用户不会因为更便宜就多买三倍的量家里摆不下。第二节假日特征有强烈的节前抬升、节后回落效应。节前3天的SHAP值显著为正节后第一周显著为负。这个结论对零售商的排产和补货非常有参考价值论文里用一条SHAP值随节前/节后天数变化的折线图展示就是很亮的可视化。第三不同品类对同一特征的敏感度差异大。家庭装洗衣液对折扣率的敏感度是旅行装洗发水的两倍多原因很简单大包装是计划性购买等促销是理性选择小包装是应急性购买价格再低也不会囤十个。5.3 把分析结果落成运营建议论文不能停在模型指标上要有落在业务上的结论。我从SHAP分析里提炼出了三条运营建议大促资源优先倾斜给家庭装和囤货型品类节前补货要提前5~7天而不是促销当天恶劣天气当日线下门店应减少日化品堆头、把资源转移到雨具和即食食品上。虽然对于纯算法项目来说这部分不是硬性要求但加入了之后论文的应用价值章节就非常扎实答辩口碑也会好不少。6. 完整项目交付源码结构、论文组织与答辩要点做毕设和做纯项目有一点不一样除了模型本身你还得交付一套完整可复现的源码、一份能过盲审的论文以及准备好一套有逻辑的答辩说辞。6.1 源码目录的设计我把整个项目按数据处理-特征工程-模型训练-评估分析-可视化五段来组织目录。顶层结构大概是这样project/ ├── data/ # 原始数据与清洗后数据 ├── src/ │ ├── data_preprocess.py # 数据清洗和商品名归一化 │ ├── feature_engineering.py # 63维特征构造 │ ├── train_lgb.py # LightGBM训练脚本 │ ├── train_lstm.py # LSTM训练脚本 │ └── evaluate.py # 模型评估与AUC/RMSE计算 ├── notebooks/ │ ├── EDA.ipynb # 探索性数据分析 │ └── SHAP_analysis.ipynb # 影响因素分析 ├── app/ │ └── dashboard.py # 简易可视化预测界面 └── docs/ └── results/ # 实验结果图表输出关键点是可复现。盲审老师和答辩老师大概率不会跑你的代码但他们可能会看目录结构是否合理、注释是否友好、README是否能把流程讲清楚所以在README里写清运行顺序和依赖版本比调一堆花哨参数更能加分。我还在requirements.txt里把lightgbm、xgboost、tensorflow、pandas、shap这些核心库固定了版本避免因为版本不对跑不起来。6.2 论文各章的写作分配论文我用了五章结构和大家分享下我心里的写作权重第一章绪论题目背景与研究意义重点写日化行业的库存管理痛点大概占8%篇幅。第二章相关技术理论线性回归、决策树集成、LSTM原理这部分不用写太深讲清楚核心思想即可大概占15%篇幅。第三章数据处理与特征工程这是毕设论文里最应该有干货的部分把所有清洗步骤和特征构造逻辑配上代码级流程图展示大概占25%篇幅。第四章模型构建与实验写清训练配置、调参过程、三组模型的对比结果和融合方案并放上RMSE/R方的汇总表格大概占30%篇幅。第五章影响因素分析SHAP结果、业务结论、运营建议大概占22%篇幅。在实验数据展示上我最喜欢用表格做模型对比。这里罗列一下我当时的结果供你参考对比模型RMSE件/天MAER方岭回归baseline17.612.30.58XGBoost11.28.10.83LightGBM9.87.20.87LSTM11.58.60.82融合模型7:39.26.70.89这套结果最大的好处是有层次baseline很差证明后续的努力有意义树模型和LSTM各有所长融合之后进一步提升——整个故事线完整且诚实。6.3 答辩时需要提前准备好的几个问题在最终答辩阶段评审老师最关注的主要有三类问题第一类是数据泄露的防范。他们经常会看你的数据划分方式。这个问题最容易暴露的问题就是用了随机打散切分。我的回答是所有时序类项目统一用TimeSeriesSplit按时间先后切分特征窗口只允许使用历史数据并且测试集的最后一段时间窗口特意避开所有训练样本。把这个讲清楚就已经能让人对你的工程严谨性建立信心。第二类是为什么选这些算法或者为什么不用更复杂的模型。我的回答关键是可解释性和任务的匹配度日化品销量预测不只是要一个数还要看清各因素如何影响销量树模型天然有可解释性优势深度学习则用来捕捉时序上的复杂模式二者互补。没必要硬凑复杂度高的模型适合数据规模和业务问题才最重要。第三类是你的结果对实际业务的应用价值。这部分直接用上一章SHAP分析出的结论来答一句话概括主要应用是找到促销和节假日的提前量用于优化补货节奏和资源配置可以让库存周转率提升几点。有落点有态度。7. 踩坑记录与个人体会整个项目做完我自己踩了几个坑写出来希望后面的人能绕开。7.1 别迷信更多数据先看清数据属不属于你一开始我尝试把180多个SKU全都丢进同一个模型去训练结果训练集确实很大但RMSE惨不忍睹。原因在于不同SKU的销量量级差异太大——家庭装洗衣液日均销量可能是旅行装洗发水的几十倍模型为了让总体误差最小基本放弃了小销量SKU。后来我改成按SKU分组训练每个SKU单独一套特征和模型效果好很多。当时为了提升训练效率对销量极低的SKU做了合并处理归入长尾组做整体预测既保住样本量又不牺牲主品精度。7.2 节假日特征千万不能只做0/1这是我在初版模型上吃过亏的地方。只做节假日标签时模型的节假日效应严重滞后它预测出的销量在节后依旧很高跟真实数据对不上。后来我把节假日细化成节前N天、节中N天、节后N天三个连续特征才把囤货-爆发-回落这个节奏表达出来。做特征工程的时候多想一想业务真实过程回报比调参高得多。7.3 正则和归一化的坑LSTM输入之前每个特征一定要单独做归一化不能对所有特征做一个统一的min-max缩放到同样范围——促销标志位这样做了之后会被压缩成0或者1这种0和1的差异在数值上可以忽略但是梯度更新的权重大小完全不同。具体做法是按列归一化每列的min和max单独计算统一存在一个scaler文件里供后续预测复用。7.4 一个关于预测未来的细节我最初设计模型的时候是用过去28天预测未来1天看起来没有毛病。但实际部署到演示系统里发现很多业务决策想要的是未来3天/7天的销量总和比如要决定一周的备货量。后来我又补了一个多步预测的评估模块用过去14天预测未来7天然后叠加成周销量。指标上误差会变大但在业务上更实用。建议做类似项目的同学提前问清楚目标不要埋头只做一个单日预测。至于这个项目后续还能怎么扩展我个人觉得比较自然的方向是多门店联合建模和新品冷启动。现在的模型对已有历史数据的品预测得很稳但如果一个门店突然上新了一个没有历史销量的SKU模型就傻了。这属于冷启动问题可以采用跨品类迁移学习来处理学类似定位老商品的历史模式把新品的预测从无到有拉起来。如果想把毕设往更好的方向打磨这是一个非常有价值的深度方向。最后分享一个我自己的体会这类销量预测项目真正拉开差距的从来不是什么难懂的数学公式而是你愿不愿意花时间把数据掰开揉碎看。促销标价、假日窗口、天气数据、陈列变动……每一个不起眼的细节都可能让RMSE掉几个点。等你在答辩台上把一条完整逻辑链讲出来——从脏数据到特征从特征到模型从模型到业务建议——你就知道这个项目带给你的不只是几十页论文而是一套面对陌生数据时的分析底气。