数学建模竞赛实战:基于需求弹性与报童模型的商品定价与补货决策
1. 项目概述从赛题到实战的完整闭环每年九月的那个周末对于全国数十万理工科学生来说都是一场没有硝烟的战争——全国大学生数学建模竞赛。2023年的C题“蔬菜类商品的自动定价与补货决策”一出来就引起了我们这些老建模人的兴趣。这题目太“接地气”了它直接把一个超市生鲜区的日常运营难题抽象成了一个需要数学、统计学和计算机科学共同解决的复杂系统问题。题目给了一份模拟的销售数据要求我们建立模型回答两个核心问题第一如何根据历史销售、损耗和成本给每种蔬菜定一个既能赚钱、又能卖得动的“聪明”价格第二每天该进多少货才能既避免缺货损失顾客又防止烂在仓库里造成浪费这不仅仅是道数学题它模拟的就是零售行业每天都在发生的真实决策。我带着团队啃下这个题目后感觉整个过程就像完成了一个微缩版的商业智能BI系统开发。从数据清洗、特征工程到模型选型、求解优化最后形成一份逻辑自洽的论文。今天我就把这套完整的解题思路、模型细节和那些“踩坑”得来的经验毫无保留地分享出来。无论你是正在备赛的学生还是对数据分析和运筹优化感兴趣的从业者相信这篇近万字的“复盘”都能给你带来直接的启发和可复现的参考。2. 核心问题拆解与建模总览面对“定价”与“补货”这两个纠缠在一起的问题第一步也是最关键的一步就是将它们清晰地解耦并定义出可量化的目标。很多新手队伍容易一头扎进数据里结果模型建得复杂却回答不了赛题最根本的提问。2.1 定价模型的核心需求弹性与利润最大化定价不是拍脑袋它的核心经济学原理是价格需求弹性。简单说就是价格变动一点销量会变动多少。对于蔬菜这种生活必需品其需求弹性通常较低即价格涨了人们也得买但可能会少买点或转向替代品但不同蔬菜之间差异巨大。比如土豆、白菜的弹性就比有机西兰花小得多。因此我们的定价模型必须能刻画这种关系。一个经典且实用的框架是建立需求函数。我们假设第i种蔬菜在第t天的需求量 ( D_{it} ) 是其自身价格 ( P_{it} )、其他相关蔬菜价格、季节性、周末效应等因素的函数。一个常用的简化形式是对数线性需求函数 [ \ln(D_{it}) \alpha_i - \beta_i \cdot \ln(P_{it}) \gamma \cdot X_t \epsilon_{it} ] 其中( \beta_i ) 就是我们需要估计的自身价格弹性系数通常为负值( X_t ) 代表其他影响因素如是否为周末、节假日( \epsilon_{it} ) 是随机误差。有了需求函数定价的目标就明确了最大化每日预期总毛利。单种蔬菜的毛利为 ( (P_{it} - C_i) \times D_{it} )其中 ( C_i ) 是单位成本进价分摊的运营成本。定价模型就转化为了一个以价格为决策变量的优化问题 [ \max_{P_{it}} \sum_i [(P_{it} - C_i) \times f(P_{it}, X_t)] ] 这里 ( f(\cdot) ) 就是上面估计出的需求函数。我们需要为每种蔬菜求解一个最优价格。注意这里有一个关键细节题目中提到了“损耗”。损耗率与销量和保鲜期强相关。在更精细的模型中预期需求量 ( D_{it} ) 需要与补货量 ( Q_{it} ) 结合考虑因为实际售出量 ( \min(D_{it}, Q_{it}) )而损耗量则与未售出的库存 ( \max(0, Q_{it} - D_{it}) ) 相关。在定价阶段我们可以先用历史平均损耗率对预期需求打一个折扣或者在后续与补货模型联合优化时再精细处理。2.2 补货模型的核心报童模型与库存平衡补货决策本质上是一个库存管理问题其经典模型是“报童模型”。报童每天要决定进多少份报纸进少了会错过销售机会缺货成本进多了卖不完就废纸一堆过剩成本。蔬菜补货一模一样只是成本结构更复杂缺货成本包括损失的利润和潜在的顾客满意度下降过剩成本就是蔬菜的损耗成本。报童模型的最优解在于平衡这两种成本的边际效应。其核心是找到最优的库存水平 ( Q^* )使得最后一单位产品被需求的概率即“不缺货的概率”等于一个临界比 [ \text{临界比} \frac{\text{单位产品缺货成本}}{\text{单位产品缺货成本} \text{单位产品过剩成本}} ] 对于蔬菜单位缺货成本可以近似为销售毛利单位过剩成本就是单位产品的成本因为烂掉全损。因此我们需要根据需求分布来求解 ( Q^* )。在实际解题中题目给出的数据是时间序列所以我们需要预测未来一天的需求分布。这就引出了补货模型的两个核心步骤需求预测利用历史数据销量、价格、时间特征等预测第t1天每种蔬菜的需求量 ( \hat{D}_{i, t1} ) 及其不确定性如预测区间的上下界。库存决策基于预测的需求分布我们通常假设为正态分布或其他分布利用上述报童模型公式计算最优的补货量 ( Q_{i, t1}^* )。同时需要考虑前一天的剩余库存 ( I_{it} )那么实际订货量应为 ( \max(0, Q_{i, t1}^* - I_{it}) )。2.3 两模型的耦合与迭代求解思路定价影响需求需求决定补货补货量影响库存成本和损耗反过来又制约定价的利润空间。这是一个耦合系统。在赛题有限的时间内一个切实可行的策略是迭代求解初始化假设一个初始价格如上期价格或成本加成价格。补货模块基于当前价格预测需求运行报童模型得到补货量。定价模块在已知补货量即最大可售量的约束下调整价格以最大化预期利润此时利润函数需考虑损耗成本。迭代将新价格代入步骤2重复2-3步直到价格和补货量变化小于某个阈值或达到迭代次数上限。这种解耦-迭代的方法在保证模型可解性的同时也较好地模拟了现实中“采购部”和“定价部”相互协调的过程。3. 数据预处理与特征工程实战赛题提供的数据通常是“脏”的直接建模等于自寻死路。数据处理阶段花的时间往往能决定模型上限的60%。3.1 数据清洗处理缺失、异常与一致性我们拿到的销售数据通常包含商品编码、日期、销售量、销售单价、损耗量、成本价等字段。缺失值处理对于偶尔缺失的销售记录若前后天数数据平稳可采用线性插值。若整日数据缺失需结合是否为闭店日如春节判断闭店日则销量、损耗均为0非闭店日则视为异常可能用周均值或同类商品均值填充。异常值检测销量为0但损耗奇高可能是盘点错误或数据录入错误应结合前后数据修正或剔除。单价异常波动检查是否因促销大幅降价或数据错误如小数点错位导致。促销点需单独标记不作为正常定价数据。负库存或销售大于补货初期存检查库存计算逻辑修正数据错误。单位一致性确保所有“量”的单位统一如千克所有“金额”的单位统一如元。3.2 特征构建让数据自己说话原始字段远远不够我们需要创造有预测力的特征。时间特征绝对时间第几周、月中第几天。周期特征星期几One-Hot编码、是否为周末、是否为法定节假日。趋势特征滚动均值如过去7天平均销量、滚动标准差表征波动性。商品关联特征类别内竞争同一大类如叶菜类其他商品的当日平均价格。替代品/互补品价格通过计算历史销量与价格的相关性找出强相关负相关为替代品正相关为互补品的商品将其价格作为特征。滞后特征这是时间序列预测的关键。包括滞后1天、7天周周期、30天月周期的销量、价格、损耗量。统计特征历史需求的变异系数标准差/均值用于衡量需求的不确定性直接影响报童模型中的安全库存计算。实操心得特征不是越多越好。开始时可以大量构建然后通过特征重要性分析如基于树模型或相关性分析进行筛选。对于线性模型要特别注意多重共线性问题。我们当时发现“星期几”和“是否为周末”这两个特征存在较强共线性最终只保留了更细致的“星期几”的One-Hot编码。3.3 数据分割与评估策略千万不要用全部数据训练然后又在同一数据上评估这会导致严重的过拟合和结果虚高。训练集/验证集/测试集划分按时间顺序划分。例如用前80%的数据作为训练集中间10%作为验证集用于调参和模型选择最后10%作为测试集用于最终模拟评估评估模型在“未来”的表现。绝对禁止随机打乱时间序列数据。评估指标定价模型在测试集上用模型给出的价格代入计算实际能获得的总毛利与使用其他策略如固定加成定价的总毛利进行对比。毛利提升百分比是最硬的指标。补货模型综合考察两个指标平均缺货率缺货量/需求量和平均损耗率损耗量/补货量。一个好的模型应在两者间取得平衡。可以定义一个综合成本函数总成本 缺货损失 损耗成本来评估不同策略的优劣。4. 模型选择、求解与结果分析这一部分是论文的核心需要清晰地展示你的建模逻辑、求解过程和结果。4.1 需求预测模型选型需求预测是定价和补货的共同基础。我们对比了几种常见模型经典时间序列模型ARIMA适合有稳定趋势、季节性的序列。但对于受价格、促销等多因素影响的蔬菜销量解释性较弱外生变量引入复杂。机器学习模型XGBoost/LightGBM能自动捕捉非线性关系和特征交互对特征工程要求高表现通常强劲。我们最终选择了LightGBM因为它训练快、能自动处理缺失值、且对类别特征友好。深度学习模型LSTM理论上非常适合时间序列。但在数据量有限通常只有1-2年日数据的赛题中容易过拟合训练时间长解释性差。我们的方案采用LightGBM回归作为主力预测模型。对于每种蔬菜单独训练一个模型。特征包括所有构建的时间特征、滞后特征、自身历史价格、关联商品价格等。目标变量是次日销量。# 伪代码示例LightGBM需求预测模型训练核心步骤 import lightgbm as lgb from sklearn.model_selection import TimeSeriesSplit # 假设 df 是准备好的特征DataFrame target 是次日销量 features df.drop(columns[‘target‘, ‘date‘]) target df[‘target‘] # 按时间顺序分割 train_idx int(len(df) * 0.8) X_train, y_train features.iloc[:train_idx], target.iloc[:train_idx] X_val, y_val features.iloc[train_idx:], target.iloc[train_idx:] # 定义模型参数 params { ‘objective‘: ‘regression‘, ‘metric‘: ‘rmse‘, ‘boosting_type‘: ‘gbdt‘, ‘num_leaves‘: 31, ‘learning_rate‘: 0.05, ‘feature_fraction‘: 0.9, ‘verbose‘: -1 } # 训练 train_data lgb.Dataset(X_train, labely_train) val_data lgb.Dataset(X_val, labely_val, referencetrain_data) model lgb.train(params, train_data, valid_sets[val_data], num_boost_round1000, early_stopping_rounds50) # 预测 demand_pred model.predict(X_val, num_iterationmodel.best_iteration) # 同时为了用于报童模型我们还需要预测区间的估计例如使用分位数回归或计算残差分布4.2 定价模型求解从函数到最优价格我们采用了对数线性需求函数。估计出弹性系数 ( \beta_i ) 后对于给定的成本 ( C_i ) 和补货量约束 ( Q_{it} )最优价格 ( P^* ) 有解析解在仅考虑自身价格弹性且需求函数形式确定的情况下 当不考虑库存约束时利润最大化的一阶条件导数为零可推导出 [ P^* \frac{\beta_i}{\beta_i 1} \cdot C_i ] 这给出了一个基准价格。但现实中必须考虑库存约束预期需求量不能超过可用库存 ( Q_{it} )。竞争与策略价格不能偏离市场平均水平太远。 因此我们最终的定价模型是一个带约束的优化问题 [ \max_{P_i} \sum_i (P_i - C_i) \cdot \min(f(P_i), Q_i) ] [ \text{s.t. } P_i^{min} \leq P_i \leq P_i^{max}, \quad \forall i ] 其中 ( P_i^{min} ) 和 ( P_i^{max} ) 是根据成本、市场价设置的合理上下限。这个问题可以用**序列二次规划SQP或启发式算法如差分进化**来高效求解。我们使用了SciPy库中的minimize函数选择‘SLSQP‘方法进行求解。4.3 补货模型求解融入预测不确定性的报童模型这是本次建模的精华所在。我们不仅预测了需求的“点估计”均值 ( \mu )还估算了其不确定性标准差 ( \sigma )。假设次日需求服从正态分布 ( N(\mu, \sigma^2) )。对于报童模型最优补货量 ( Q^* ) 满足 [ F(Q^*) \frac{C_u}{C_u C_o} ] 其中 ( F(\cdot) ) 是需求分布的累积分布函数CDF( C_u ) 是单位缺货成本近似为毛利 ( p - c )( C_o ) 是单位过剩成本即成本价 ( c )因为损耗全损。因此计算步骤为计算临界分位数 ( \phi C_u / (C_u C_o) )。对正态分布求其逆累积分布函数PPF( Q^* \mu z_{\phi} \cdot \sigma )。其中 ( z_{\phi} ) 是标准正态分布的 ( \phi ) 分位数。当 ( \phi 0.5 ) 时即毛利较高缺货成本高( z_{\phi} 0 )需要设置安全库存反之则 ( z_{\phi} 0 )可以激进地少进货。实际计算示例 假设预测菠菜次日需求均值 ( \mu 100 ) 公斤标准差 ( \sigma 20 ) 公斤。成本价 ( c 4 ) 元/公斤根据定价模型得出售价 ( p 6 ) 元/公斤。则单位缺货成本 ( C_u p - c 2 ) 元单位过剩成本 ( C_o c 4 ) 元临界比 ( \phi 2 / (24) 0.333 )查标准正态分布表( \phi 0.333 ) 对应的 ( z_{\phi} \approx -0.43 )最优补货量 ( Q^* 100 (-0.43) \times 20 91.4 ) 公斤。这个结果符合直觉菠菜毛利不高2元过剩成本却很高4元因此策略偏向保守补货量略低于预测均值以优先控制损耗。4.4 结果分析与可视化模型建得好不好需要用数据说话。定价效果对比绘制测试集上采用模型动态定价与采用固定成本加成定价如统一加价30%的每日毛利对比折线图。计算整个测试期内的总毛利提升率。补货效果对比用“牛鞭图”或双Y轴折线图同时展示每日的预测需求、实际需求、模型补货量和实际库存。可以清晰看到模型是如何跟随需求波动并提前做出反应的。库存健康度分析统计测试期内平均库存周转天数、缺货商品天数占比、高损耗损耗率10%商品天数占比等业务指标与基线策略进行对比。敏感性分析展示当成本价波动±10%或需求预测误差增大时模型总利润的变动情况说明模型的鲁棒性。5. 论文写作要点与常见陷阱规避数学建模竞赛“建模”和“论文”各占半边天。一个优秀的模型需要一个清晰的表达。5.1 论文结构框架摘要重中之重用300-500字浓缩全部精华。必须包含问题重述、你的核心模型名称、求解方法、主要结论用具体数据如“总毛利提升15.2%”、“平均缺货率降低至3.1%”和模型特色。问题重述与分析不要照抄题目要用自己的语言梳理出问题的逻辑脉络、核心目标和约束条件。画出“定价-补货”决策的逻辑流程图让评委一眼看懂你的解题思路。模型假设合理且必要的假设是模型的起点。例如“假设同一品类内蔬菜的需求相互影响”、“假设短期内蔬菜的成本价格保持不变”、“忽略极端天气等突发外部因素”。每一条假设都要说明其合理性。符号说明用三线表清晰列出所有主要变量、符号及其含义方便评委查阅。模型建立与求解这是论文的主体。对应我们前面的第2、4部分。分小节阐述需求预测模型、定价模型、补货模型以及它们的耦合方式。每一个模型都要有公式推导、参数说明和求解过程描述。模型检验与结果分析对应第4.4部分。展示实验结果用图表说话并配以文字分析。进行灵敏度分析讨论模型优缺点。模型评价与推广客观评价自己模型的优点如综合考虑定价与补货、实用性强和缺点如未考虑供应商约束、假设需求分布为正态可能偏差等。提出改进方向如引入更复杂的需求分布、考虑多周期优化。参考文献与附录参考文献格式规范。核心代码、大型数据表格、复杂推导过程可放在附录。5.2 常见“踩坑点”与应对策略把赛题当预测题做只做了精细的需求预测然后简单地用预测销量去决定补货用成本加成法定价。这完全忽略了“决策优化”的核心。对策时刻牢记目标是“决策”定价、补货量预测只是为决策服务的工具。必须在模型中体现“优化”的过程。模型复杂解释不清用了非常复杂的集成模型或深度学习但在论文中无法清晰解释其机理也说不清某个参数的意义。这会让评委怀疑你是否真懂。对策优先选择可解释性强的模型。如果用了复杂模型必须用特征重要性图、SHAP值等工具进行解释并在附录提供关键代码。忽略不确定性补货模型只用了预测的均值没有考虑预测误差导致模型在实际波动面前非常脆弱。对策必须将需求的不确定性方差、预测区间量化并融入到报童模型的决策中。数据预处理一笔带过论文中只写“对数据进行了清洗”没有具体说明处理了哪些异常、如何填充缺失值。这是扣分点。对策在论文中单独用一小节或一个表格说明数据预处理的具体步骤和规则。结果分析空洞只说“模型效果很好”没有与基线模型对比的具体数据也没有图表支撑。对策设计明确的基线策略如固定价格、历史均值补货用表格和图表多维度对比关键指标总利润、缺货率、损耗率。编程与论文脱节论文里的模型描述和实际代码对不上。对策先搭建好核心模型的代码框架再根据代码实现去撰写论文模型部分确保二者一致。论文中的公式最好能用代码复现其计算过程。这次国赛C题的旅程让我再次深刻体会到一个好的数学模型永远是业务逻辑的数学化表达。从理解“定价”和“补货”这两个商业动作的本质开始到用数学语言描述它们之间的博弈最后通过编程和算法让机器给出量化决策这个过程本身就是一个极佳的思维训练。最后给备赛同学的建议是拿到题目后别急着找文献套模型先花足够的时间和小组成员一起像真正的超市经理一样把这个问题掰开揉碎地讨论清楚。当你们对业务逻辑的共识足够深时数学模型自然就会浮现出来。