2023 国赛 C 题模拟赛完整复盘(蔬菜定价与补货)

时间:8/16–8/19 我应该没有摸鱼吧

仓库:https://github.com/Raisetsu41/MCM/

赛题与数据

题目:2023 高教社杯 C 题《蔬菜类商品的自动定价与补货决策》。

四问:

  1. 分析各蔬菜品类/单品销售量的分布规律及相互关系;
  2. 以品类为单位,分析销售总量与成本加成定价的关系,给出未来一周(2023-07-01~07)的日补货总量与定价策略;
  3. 单品层面:可售单品 27–33 个、最小陈列量 2.5 kg,根据 6/24–30 可售品种给出 7/1 的单品补货量与定价;
  4. 还需要采集哪些数据、对解决上述问题有何帮助。

附件:

附件内容规模
附件1商品信息(6 品类 251 单品)251×4
附件2销售流水878,503 行,2020-07-01 ~ 2023-06-30(T=1095 天)
附件3批发价格55,982 行
附件4损耗率(单品级 + 分类级)251+6 条

清洗口径:退货按负销量并入当日净销量;单品日表 46,599 行、品类日表 6,474 行;有销售单品 246 个(5 个无销售记录)。

团队与分工

我以为”割裂分工”是比较糟糕的,所以约定:每个问题三人共同参与建模讨论,代码由我主要承担,论文统稿由 ljh 负责,lzy 主建模。实践下来效果不错,但后期统稿压力集中。

协作规范(COLLABORATION.md):

  • 一人统稿:维护 main.tex、摘要、ref.bib、附录;
  • 一人主建模、一人主代码,每个问题设 lead,其他人交叉 review;
  • 尽量只改自己负责的 .tex 文件,main.tex/ref.bib 由统稿人改;
  • main 分支只放能编译的稳定版本,大改动开 feature/<名字>-<内容>;
  • 提交信息用动词开头;提交前 git pull --rebase origin main;
  • 提交前本地 xelatex 编译通过。

工作流(这次用的流程)

整体按”分析 → 建模 → 编码 → 绘图 → 写作 → 验收”的流水线推进,产物都落在 workspace/:

2analysis-modeling(建模稿)
  → 3coding-visual(代码 + 图表 + RESULTS_REPORT)
  → 4drawio(非数据图)
  → 5writing(论文章节)
  → 6verity(最终验收)
  • 建模稿里我习惯用 [cjg] 补丁标注修正,保留队友原文、只追加说明;
  • 所有关键数字都留 CSV/JSON 证据,论文只引用 results/ 里的值。

问题一:分布、季节、关联、聚类

思路

拆成四个递进的子模型:

  1. 分布模型:品类日销量用 lognormal/gamma 拟合(AIC 选型、BIC 核对);单品大量零值 → 两阶段混合分布(售出概率 + 条件正销量分布);
  2. 季节模型:STL 分解周内季节(period=7, robust=True),年季节用月度聚合;
  3. 协同网络:星期/月份虚拟变量残差化后取 Spearman 秩相关,BH-FDR 校正,前后半样本稳健边建网;
  4. 聚类:六维时序特征(售出占比/有售日均/变异系数/周末偏置/节假日脉冲/销量占比)+ z-score + Ward 层次聚类。

关键结果

项结果
品类分布gamma 4 个(花叶/花菜/水根/茄),lognorm 2 个(辣椒/食用菌),AIC=BIC 一致
单品分布132 个进入参数拟合(gamma 81 / lognorm 51),售出概率 0.0557~0.9826
STL季节强度 0.17290.2616,趋势强度 0.51350.6268
旺季检验茄类 1.5412、花叶 1.0945、花菜 1.0089 大于 1,其余品类淡季反而更高
协同网络8,646 对中主边 1,062(正 820 / 负 242),稳健边 154、51 节点
品类相关花叶-食用菌 0.651、花叶-辣椒 0.636、辣椒-食用菌 0.638
聚类k=5,silhouette 0.2583,80% 抽样 50 次 ARI 0.4567

插曲:伪篮子的证伪

一开始想用(日期, 扫码时间)构造伪交易 ID 跑 Apriori,结果在附件 2 上实测:同秒多件不同单品交易的占比极低,且无法排除多台收银机并发,属于伪回归。于是放弃关联规则,把颗粒度上卷到日频做协同网络——这个”先证伪再换方法”的过程最后也写进了建模稿。

问题二:弹性 → 加价率 → 预测 → 报童

模型链

最优加价率:常弹性下 求导得 ()。但实测六品类全是弱弹性(),利润在可行域内单调 → 历史加价率区间 网格搜索的边界解。

预测:先用弹性把历史销量折算到参考价的”去价格序列”,再做含趋势/星期/月份的回归外推(对数均值修正 ),最后按最优价乘性缩放。

报童:,分位数用 lognormal 矩匹配(与问题一分布口径衔接),补货量 。

关键结果

品类弹性t 值最优加价率最优售价
花叶类-0.45-6.791.017.22
花菜类-0.50-5.450.7114.00
水生根茎类-0.07-0.70(不显著)0.4416.07
茄类-0.26-3.160.907.81
辣椒类-0.13-3.031.146.79
食用菌-0.31-5.280.824.53
  • 未来一周:总补货 2607.89 kg,总期望利润 5305.19 元;
  • 补货呈周末集中结构(7/1+7/2 占全周 36.2%);
  • 水生根茎类弹性不显著,定价结论降级为”证据不足”;
  • 报童 vs 确定性订货:5305.19 vs 4550.45 元(+754.74),报童更少订(负安全库存,)但期望利润更高;
  • 回测:后 28 天 MAPE 20.6%~37.2%;2022-07 同期回测 23.9%~66.4%(跨年稳定性有限)。

纠结:Q-P 模型 vs k-π 推导

这轮里纠结最多的是:需求侧明明建的是 模型,定价策略那边为什么用加价率 推导?

理顺后的口径:顾客只能看到货架价 P,加价率 是派生输出,不是需求自变量。4.2 本来就是价格空间求导;4.3 的网格搜索也是”对夹逼后最终价格评估利润”。弱弹性下利润单调、最优恒在边界,所以可行域口径(加价率区间 vs 价格区间)直接决定数字——这也是为什么”中位价口径 +72.8%“这种看似离谱的结果其实是口径问题。

联合定价扩展:直接用 6×6 交叉弹性 + 差分进化,独立与联合同在价格可行域 下比较:独立 3265.50 vs 联合 3861.36 元/日(+18.2%);交叉项 15/30 显著(9 正 6 负),仅显著项 +15.6%、缩半 +5.4%。

问题三:单品级选品、定价与补货 MIP

模型

  • 候选集:6/24–30 有售且周均净销量 ≥ 0.5 kg/天 → 45 个(有售 49 个剪枝后;花叶 16/辣椒 9/食用菌 8/水根 6/茄 4/花菜 2);
  • 单品弹性:Log-Log 回归 + Shrinkage 收缩 (, 或无变异直接借品类弹性;12/45 借用品类弹性);
  • 价格网格:历史 等距 11 档,参考价 显式并入网格;
  • 0-1 MIP(HiGHS):同时决策上架/选档/订购,目标 = 收入 − 进货成本 − 缺货惩罚;
  • 约束:、、定价唯一、、缺货量定义、品类覆盖。

关键结果(7/1)

指标数值
选中单品33(花叶 11/辣椒 8/食用菌 6/茄 3/水根 3/花菜 2)
总订购量296.83 kg
总销量 = 总需求270.14 kg,满足率 1.00
总收入 / 总成本 / 总利润1915.69 / 1233.61 / 682.08 元
求解状态HiGHS optimal,gap=0,节点数 1,无降级
陈列刚性超订1.16 kg(10.53 元,3 个低需求单品被最小陈列卡到 2.5 kg)

收缩后单品弹性区间 ;小米椒(份) 单品毛利 109.49 元最高。

问题四:数据采集建议

五维方案,正文只留 2 页:

  1. 需求侧:会员 ID + 购物篮(Lift 识别互补/替代)+ 缺货登记(修正截断低估);
  2. 市场侧:货架拓扑 + 竞品实时均价 → 交叉价格弹性 ,替代效应按货架距离衰减;
  3. 运营侧:分时段库存 + 打折流水 → 日内动态定价(贝尔曼方程)叠在日级报童之上;
  4. 供给侧:分环节损耗率 + 供应商履约指数 → 时变损耗函数 + 提前期安全库存;
  5. 外部环境:天气/节假日/促销日历 → 回归外生变量,去混淆弹性。

优先级:外部环境(极低)> 需求侧 > 运营侧 > 供给侧 > 市场侧(高成本)。

模型检验与灵敏度

七项量化检验,阈值全部运行前声明,契约在 results/q2_robustness_summary.json:

检验项观测值状态
批发价 ±10%利润变化 <1%PASS
弹性 ±20%利润变化 <0.5%PASS
价格口径切换中位价口径 +72.8%、弹性符号翻转CONDITIONAL
报童 vs 确定性+754.74 元PASS
损耗率替换补货量 -1.0%PASS
2022-07 同期回测MAPE 最高 66.4%(>40%)CONDITIONAL
品类相关联合模拟期望利润偏差 +0.11%,方差比 2.47PASS

问题三灵敏度(14 个情景重解 MIP):批发价是最敏感输入(利润 -17.6%/+18.1%),选品数 27/30/33 → 657.54/673.60/682.08,网格离散化影响 ±4.5%,rho 和大 M 完全不变。

论文与页面控制

页码历程

初稿全篇(含附录代码)一度超过 100 页 → 通过压缩正文到 约 30 页(参考文献 4 页、附录约 65 页不计页数)。最终正文分布大致:封面+摘要 3、引言假设 1、Q1 7、Q2 10、Q3 4、Q4 3、检验+评价 4。

ljh 复盘里的页面控制经验

  • 写作时给每个 section 定页数区间,并标注图表是否必须;
  • 窄行多的表格改成并列/紧凑形式控制表高;
  • 图表位置用 [H] 固定,避免 htbp 乱跑留大片空白;
  • 每部分定稿后由论文手先做一轮页面控制,不要等到最后;
  • 参考文献 58 条偏多,注意中文文献占比,避免”全是英文 → 像 AI 生成”的观感。

验收发现的坑

  • ref.bib 出现过重复 key(silver2016),bibtex 直接报错;
  • 引用了不存在的 \ref{sec:sensitivity},编译出 ”??”;
  • 附录表格出现 ”—” 占位符没填;
  • 硬编码”见第九章/9.1.1”这类章号,删改章节后全错,应该用 \ref;

踩坑与复盘汇总

Git / 协作

问题解决
push/pull 连接不稳定改用 SSH 协议
提交后队友不知道改完在群里说一声
冲突提交前 git pull --rebase origin main;只改自己的文件
前期分工不均每节定结果后立即排版引用,别把活堆给统稿人

建模 / 代码

  • 伪关联要证伪:扫码时间构造伪篮子不可行,日频上卷才是对的;
  • 价格口径决定一切:固定基期权重防”当期加权 → 机械负相关”;
  • 弱弹性下”最优”是历史区间约束下的最优,论文必须写明边界;
  • 缺货截断会让净销量低估真实需求(Q2/Q3 共享局限);
  • 7/1 是周六但没做周末偏置,列为局限;

流程上的改进点(下次比赛)

  • 定选题后尽快完善文档并标 deadline;
  • 论文手前期就参与排版,别让最后 48 小时集中爆发;
  • 图表移位/流程图问题提前准备替代方案(比如外部工具出图再插入);
  • 参考文献从一开始就控制数量和质量。

仓库一览

MCM/
├── README.md / COLLABORATION.md / NOTES.md
├── materials/            # 模板与参考资料(只读)
├── Problem/              # 赛题 + 附件 1-4
└── workspace/
    ├── main.tex          # 论文主文档
    ├── sections/         # 00 摘要 ~ 09 附录
    ├── draft/            # 建模稿 + RESULTS_REPORT
    ├── code/             # clean_data.py, question1/A-D.py,
    │                     # question2/nv.cpp+q2.py+q2_sensitivity.py,
    │                     # question3/q3.py
    ├── results/          # 清洗数据与全部结果 CSV/JSON
    ├── figures/          # 论文图表 PDF
    └── fonts/            # 模板字体(勿动)

编译:xelatex main.tex && bibtex main && xelatex main.tex && xelatex main.tex。

相关笔记