1. 赛题核心与破题方向:从“蔬菜类商品”到“供应链优化”的思维跃迁
拿到2023年国赛C题“蔬菜类商品的自动定价与补货决策”时,很多队伍的第一反应是去找价格预测模型或者库存管理公式。这没错,但容易陷入局部最优。这道题的精妙之处在于,它表面上问的是“定价”和“补货”,本质上考的是在不确定需求下,如何构建一个动态、协同的供应链决策系统。它要求你不仅会算,更要会“想”,把零散的销售数据、损耗数据、品类关系,整合成一个能指导未来行动的智能决策框架。
题目给了我们几个核心约束和场景:一家生鲜商超,每天要决定各种蔬菜的售价和补货量。目标是让商超的整体收益最大化。这里面的难点层层递进:首先,蔬菜易腐,当天卖不完就损耗,直接成本吞噬利润;其次,不同品类蔬菜之间可能存在替代或互补关系,一个菜涨价了,顾客可能转头去买另一个;最后,销售数据里充满了“噪声”——周末效应、节假日、促销活动、甚至天气,都会让需求曲线上下跳动。官方附件提供了过去三年多的销售流水、损耗记录和商品分类信息,这就是我们全部的“矿藏”。
所以,我们的思路绝不能停留在简单的回归预测上。一个高分的模型,必然是一个**“感知-预测-决策-评估”的闭环系统**。你需要用统计和机器学习方法从历史数据中“感知”规律(如需求弹性、损耗率、品类关联),基于这些规律“预测”未来一天各单品在给定价格下的销量和损耗,然后建立一个优化模型来“决策”最优的价格和补货量组合,最后还要设计一套方法来“评估”这个决策模型在未知数据上的表现是否稳健。这四步,环环相扣,缺一不可。接下来,我就结合我们团队的实战经验,拆解每一步的具体做法、可选模型、以及那些容易掉进去的“坑”。
2. 数据感知与特征工程:从原始流水到模型“燃料”
附件中的数据是典型的零售业数据,看似规整,实则暗藏玄机。直接丢给模型效果肯定不好,必须经过精心清洗和特征构建。
2.1 数据清洗与整合:解决“脏数据”问题
销售流水表是核心,但里面有很多陷阱。首先就是缺失值与异常值。某些天某些单品完全没有销售记录,这可能是缺货,也可能是当天未上架。我们的处理原则是:对于连续多天无记录的单品,在对应日期填充为0销量和0损耗;对于偶尔一天无记录但前后都有销售的,可以考虑用前后天的均值或插值法填充,但要谨慎,最好结合损耗记录表判断——如果当天有损耗记录却无销售,那很可能是数据录入遗漏,销量应为0。
其次是数据一致性。销售表中的“销量”是实际售出,而“损耗量”在另一个表里。必须通过“单品编码”和“日期”将两个表精确关联,得到每个单品每日的“进货量”(销量+损耗量)。这里有个关键校验:计算出的“进货量”是否总是整数?理论上是的,因为蔬菜按份卖。如果出现小数,可能是数据合并或单位问题,需要排查。
2.2 核心特征构建:提炼影响决策的关键信息
清洗后的数据是“原料”,特征工程则是“烹饪”,决定模型的最终味道。我们构建了以下几类特征:
- 时序特征:这是基础中的基础。包括年、月、日、星期几、是否为周末、是否为月初/月末、是否为节假日(需外部日历数据)。特别注意,国庆、春节等长假前后需求模式会剧变,最好能标识出来。
- 历史统计特征:基于滚动窗口计算,这是体现“惯性”和“趋势”的关键。
- 需求水平:过去7天、14天、30天的平均销量。
- 需求波动:过去7天、14天销量的标准差、变异系数(标准差/均值),用来衡量需求的不确定性。
- 价格弹性初探:可以计算过去一段时间内,销量与价格之间的相关系数(虽然简单,但能提供初步信号)。
- 品类与关联特征:这是本题拉开差距的地方。
- 品类聚合特征:同一个二级类(如“叶菜类”)下的所有单品,其总销量、平均价格可以作为该品类整体行情的代理变量。
- 替代/互补品特征:这是难点。我们采用了两步法:首先,计算各单品间销量序列的相关系数,找出高度正相关(可能受共同因素驱动)或高度负相关(可能存在替代关系)的品对。然后,将关联性最强的3个单品的价格和销量作为特征,引入目标单品的模型中。例如,菠菜的价格,可能会受到小白菜(替代品)价格和销量的显著影响。
- 损耗相关特征:损耗率(损耗量/进货量)是核心成本。可以计算单品的历史平均损耗率、损耗率的波动性。一个高损耗率且波动大的单品,在定价和补货时必须更加保守。
- 滞后特征:将前1天、前7天(同期,比如都是周二)的价格、销量、损耗率作为特征,因为市场需求往往具有短期记忆和周期性。
注意:特征不是越多越好。高度相关的特征会导致模型过拟合或不稳定。一定要进行特征重要性分析(如基于树模型)或相关性分析,剔除冗余特征。我们当时用XGBoost初步跑了一个重要性排序,发现“前7天平均销量”、“星期几”、“历史损耗率”和“替代品价格”是最重要的几个特征。
3. 需求与损耗预测模型:不确定性下的“水晶球”
有了高质量特征,下一步就是预测:如果我明天给某个单品定价为P,预计能卖出多少(需求D)?又会有多少损耗(L)?这里有两个核心模型。
3.1 需求预测模型:价格与销量的博弈
需求预测模型需要刻画价格-销量关系。简单线性回归(销量 = a * 价格 + b)太理想化,不符合经济学常识(价格越高,需求通常越低,且关系可能非线性)。我们推荐以下几种方法:
经典需求函数拟合:直接采用经济学中的需求函数形式进行拟合。
- 线性需求函数:
D(p) = a - b * p(a, b > 0)。虽然简单,但在局部价格区间内可能有效。 - 指数需求函数:
D(p) = a * exp(-b * p)。能刻画需求随价格上升而加速下降的现象。 - 幂函数需求函数:
D(p) = a * p^(-b)(即常价格弹性函数,弹性为-b)。这是非常常用且具有良好经济学解释的模型,价格弹性恒定。 拟合时,将价格p作为自变量,销量D作为因变量,利用历史数据通过最小二乘法或最大似然估计求解参数a, b。但这里有个大坑:历史数据中的价格和销量是已经发生的“均衡结果”,可能存在内生性问题(即价格本身可能根据预期销量已经调整过)。更严谨的做法是使用面板数据模型或引入工具变量,但对数理基础要求高。
- 线性需求函数:
机器学习模型:更灵活,能自动捕捉非线性关系和特征交互。
- XGBoost/LightGBM:非常适合表格数据,能高效处理特征,并提供特征重要性。我们可以构建一个模型,输入特征包括:计划定价
p、历史特征、时序特征、品类特征等,直接输出预测销量D_hat。关键技巧:在训练时,p(价格)是作为一个特征加入的。但在预测时,p是我们要优化的决策变量。这意味着我们需要为每一个可能的p值(在一个合理范围内)都做一次预测,来描绘出大致的需求曲线D(p)。 - 神经网络:如果有足够数据,可以尝试简单的全连接网络。但相对于树模型,它可解释性差,且更容易过拟合,在数模竞赛中需谨慎使用。
- XGBoost/LightGBM:非常适合表格数据,能高效处理特征,并提供特征重要性。我们可以构建一个模型,输入特征包括:计划定价
我们的选择与理由:我们采用了混合策略。首先,用XGBoost训练一个基础需求预测模型,特征中包含历史价格。然后,对于每个单品,我们固定其他特征,让价格p在历史价格的最小最大值区间内以一定步长变化,用模型预测出一系列(p, D_hat)点,再用这些点去拟合一个幂函数需求曲线D(p) = a * p^(-b)。这样做的好处是:既利用了机器学习模型强大的特征学习能力,又将最终的需求关系约束在一个符合经济学直觉、且易于后续优化求解的简洁数学形式上。拟合出的b值就是该单品在当前市场环境下的预估价格弹性。
3.2 损耗预测模型:成本控制的“预警机”
损耗预测相对直接,因为损耗主要与进货量(即补货决策)和商品本身特性有关,对价格不敏感(我们假设定价不影响损耗率)。可以建立一个预测损耗率r的模型。
- 因变量:损耗率
r = 损耗量 / 进货量。注意处理进货量=0的边界情况。 - 自变量:包括单品类别、历史平均损耗率、进货量(预测值)、季节(夏季损耗可能更高)、是否为易腐品类(如叶菜类)等。
- 模型选择:由于损耗率是介于[0,1]之间的连续值,可以考虑使用Beta回归或分位数回归。更实用的是,使用梯度提升树(如LightGBM)直接回归,并在训练时对目标变量
r做适当的压缩变换(如logit变换),效果也不错。
预测时,我们需要先有一个补货量Q的预估值(初始可设为历史均值),代入模型预测出损耗率r_hat,则预测损耗量L_hat = r_hat * Q。
4. 定价与补货联合优化模型:寻找收益最大化的“甜蜜点”
这是整个赛题最核心的部分,也是论文的亮点所在。预测模型告诉我们“如果这样,可能会怎样”,而优化模型则回答“到底应该怎样”。
我们的目标是最大化商超每日的总收益。对于单品i,设其定价为p_i,补货量为Q_i,预测需求为D_i(p_i),预测损耗率为r_i(可能依赖于Q_i和其他因素),则:
- 实际销量为
min(D_i(p_i), Q_i * (1 - r_i))。这里假设损耗发生在销售之前或之中,可供销售的量为Q_i * (1 - r_i)。 - 收益 = 销售收入 - 成本 =
p_i * min(D_i(p_i), Q_i * (1 - r_i)) - c_i * Q_i。其中c_i是单品的进价(成本价)。
那么,总收益最大化问题可以形式化为一个约束优化问题:
目标函数:Maximize:Σ [ p_i * min(D_i(p_i), Q_i * (1 - r_i)) - c_i * Q_i ](对所有单品i求和)
约束条件:
p_i_min ≤ p_i ≤ p_i_max(价格上下限,通常基于历史数据或政策设定)0 ≤ Q_i ≤ Q_i_max(补货量上限,可能由供应商或仓储能力决定)D_i(p_i)是第3步中得到的需求函数(如a_i * p_i^(-b_i))。r_i可能是常数,也可能是Q_i的函数(如进货越多,管理越难,损耗率微增)。
难点与解决方案:
min()函数导致非光滑:目标函数中的min()使其不光滑,难以直接用梯度类算法求解。处理方法有两种:一是引入辅助变量和不等式约束,将其转化为线性或非线性规划问题;二是采用分情况讨论,由于最优解通常倾向于让补货量略高于需求以避免缺货损失,我们可以先假设Q_i * (1 - r_i) ≥ D_i(p_i),即货源充足。这样目标函数简化为Σ [ p_i * D_i(p_i) - c_i * Q_i ]。求解后,再验证该假设是否对所有单品成立。若不成立,对不满足的单品调整假设重新求解。- 品类关联性:目标函数是各单品收益的简单求和,忽略了替代效应。更高级的模型可以引入交叉价格弹性。假设单品i和j互为替代品,那么i的需求不仅取决于
p_i,还取决于p_j:D_i = a_i * p_i^(-b_ii) * p_j^(b_ij),其中b_ij > 0表示j的价格对i需求的影响。这样目标函数就变成了一个复杂的非线性方程组,求解难度极大。在竞赛有限时间内,一个可行的简化是:分层次优化。先对每个品类内部(替代性强)的单品进行联合优化,再在品类间进行协调。或者,将关联性强的单品打包,为这个“包”设定一个总补货量约束,然后在包内分配。 - 求解算法:
- 如果模型能简化为无约束或简单约束的凸优化问题,可以使用梯度下降法、牛顿法等。
- 对于带约束的非线性规划,可以使用序列二次规划(SQP)或内点法,调用MATLAB的
fmincon函数或Python的SciPy.optimize.minimize工具包。 - 智能优化算法:当变量较多(几十上百个单品),问题非凸时,遗传算法(GA)、粒子群算法(PSO)是很好的选择。它们能全局搜索,虽然不能保证找到理论最优,但通常能找到高质量的可行解。我们当时采用了差分进化算法(DE),因为它参数少、收敛性相对好,非常适合这类连续变量的优化问题。我们将每个单品的
(p_i, Q_i)编码为一个个体,以总收益的负值作为适应度函数,进行迭代进化。
5. 模型评估与策略分析:不只是数字游戏
优化模型输出了一套(p_i, Q_i),但它的效果到底如何?不能只靠目标函数值说话,必须进行回溯测试和场景分析。
5.1 回溯测试(Backtesting)
从历史数据中划出一部分作为“测试期”(例如最后一个月)。用测试期之前的数据训练我们的预测模型和优化模型。然后,模拟在测试期的每一天:
- 基于截至前一日的历史数据,运行优化模型,得到当天各单品的建议定价和补货量。
- 将这些建议值“应用”到当天。但这里有个问题:我们无法知道如果用了建议价格,真实需求会是多少。所以我们需要一个“反事实估计”:利用我们之前拟合的需求函数
D_i(p),将建议定价p_i代入,计算出预测需求D_hat_i。 - 模拟过程:实际销量 =
min(D_hat_i, Q_i * (1 - r_i)),其中r_i用预测的损耗率。然后计算模拟的当日收益。 - 将整个测试期的模拟收益加总,与测试期实际发生的收益进行对比。同时,对比模拟的销量、损耗量与实际情况的差异。
注意:这个对比不是看绝对数字是否一致(因为价格变了,需求也变了),而是看趋势和优化效果。一个成功的模型应该能显示出:在模拟中,通过优化定价和补货,总收益相比实际历史收益有显著提升,同时平均损耗率有所下降。
5.2 敏感性分析与策略解读
模型不是黑箱,我们需要理解它为什么做出这样的决策。
- 价格弹性分析:展示不同单品拟合出的价格弹性系数
b。弹性高的单品(如常见绿叶菜),降价能显著提升销量,适合做促销引流;弹性低的单品(如必需调味品或特色菜),顾客对价格不敏感,可以维持较高利润率。 - 补货策略分析:分析优化后的补货量
Q_i与历史平均销量的比值。对于损耗率高、需求波动大的单品,这个比值通常会比较保守(即少进多补);对于畅销且稳定的单品,比值会更高。 - “如果-那么”场景分析:这是论文的加分项。例如:
- 场景一(成本上涨):假设所有单品进价
c_i统一上涨10%,重新运行优化模型,观察最优定价和补货策略如何调整,总收益变化多少。 - 场景二(需求波动):模拟节假日(需求整体上浮20%)或恶劣天气(需求下浮15%,但可能某些品类需求上升),看模型的应对策略。
- 场景三(捆绑促销):如果强制要求某两种关联单品(如西红柿和鸡蛋)进行捆绑定价(总价打折),对整体收益有何影响? 通过这些分析,你的模型就从一套数学公式,升华为一个能为管理者提供深度洞察的决策支持系统。
- 场景一(成本上涨):假设所有单品进价
6. 论文写作与编程实现要点
思路再好,也需要通过论文和代码来呈现。
6.1 论文行文逻辑
- 问题重述与分析:不要照抄题目,要用自己的话精炼概括问题的本质、目标和约束,并画出逻辑框图,清晰展示“数据->预测->优化->评估”的流程。
- 模型假设:清晰列出关键假设,如“假设单品间的替代效应主要通过品类聚合特征刻画”、“假设损耗率在短期内相对稳定”等。合理的假设能简化问题,体现你的思考。
- 符号说明:制作一个三线表,列出所有主要变量、符号及其含义,方便评委查阅。
- 模型建立:这是核心章节。分小节详细介绍预测模型(需求、损耗)和优化模型。对每个模型,要交代为什么选这个模型(与其它模型对比的优劣),模型的具体形式(给出数学公式),以及参数如何估计或学习。
- 模型求解:详细说明你采用的算法(如差分进化算法),包括编码方式、种群大小、迭代次数、变异交叉策略选择等参数设置,并解释为什么这些参数是合理的。可以附上算法流程图。
- 模型检验与结果分析:展示回溯测试的结果对比图、表。进行深入的敏感性分析和场景分析。所有结论都要有图表或数据支撑,避免空谈。
- 模型评价与推广:客观评价自己模型的优点(如综合考虑了多种因素、实用性强)和缺点(如对数据质量依赖高、未考虑突发极端事件)。提出可能的改进方向,并将模型推广到更一般的零售商品定价补货问题。
6.2 编程实现技巧
- 语言选择:Python是首选,生态丰富。Pandas用于数据清洗,Scikit-learn/XGBoost/LightGBM用于预测模型,SciPy用于优化,Matplotlib/Seaborn用于绘图。
- 代码结构:按模块组织代码:
data_preprocessing.py,feature_engineering.py,demand_forecast.py,loss_forecast.py,optimization.py,evaluation.py。这样清晰且易于调试。 - 效率优化:优化模型求解可能是计算瓶颈。对于智能算法,设置合理的迭代次数和种群规模。可以考虑并行计算(如评估种群中个体的适应度函数时可以并行)。
- 结果可视化:不仅要画出销量-价格散点图及拟合的需求曲线,还要画出优化前后各单品价格/补货量的对比雷达图或条形图,以及总收益随时间变化的对比折线图。一图胜千言。
最后想说的是,国赛C题从来不是要一个完美的、能直接商用的系统,而是考察你们将复杂实际问题抽象为数学模型的能力、对多种建模方法的理解和驾驭能力、以及通过编程和数据分析解决问题的能力。大胆假设,小心求证,在模型复杂性和可解释性之间找到平衡,并用严谨的论文和可靠的代码将其呈现出来,这就是通往高分的道路。我们当时在最后一天,发现最初的优化模型在某个特殊品类上结果反常,连夜回溯,发现是给该品类设定的价格下限不合理,导致模型搜索空间受限。所以,永远要对模型结果保持怀疑,用业务常识去校验它,这个反复调试、思考、完善的过程,或许比最终的答案更重要。