案例 096 商家取消订单
案例 096 商家取消订单
摘要:到店发现商家取消或缺货,白跑 8 min 折 1.6 元。平台推"取消费补偿险":1.0 元/天,每次取消赔 2.0 元。本文建 0-1 期望值模型,用 Gurobi 求"买/不买",并把补偿口径拆成两档:按损失补偿原则(赔付不超过 1.6 元损失),买险后日成本从 1.44 元降到 1.00 元、日省 0.44 元;若允许超额赔付,日成本降到 0.64 元、日省 0.80 元。题面"\(1.44>1.00\)"的结论只在封顶口径下严格成立。把模型推广到 \(n\) 单,得临界单量 \(n^*=q/(p\bar c)=20.8\) 单——单量低于 20.8 单不该买,这是本案的主结论。方差视角下,买险把标准差从 1.49 元压到 0、CV 从 1.04 压到 0,保险卖的是确定性而非期望。灵敏度显示取消率 1% 时临界升到 62.5 单、6% 时降到 10.4 单,补偿降到 0 则任何单量都不该买。
关键词:保险决策;期望值模型;0-1 规划;临界单量;风险确定性
1 问题提出
外卖小哥骑到商家门口,卷帘门拉着,贴一张纸:"今日原料售罄,订单已取消。"这一趟白跑:往返 8 min,电费、折旧和时间成本摊进去按 1.6 元计。这种事不常有,但天天跑就一定会碰上——平台数据显示,广州城区午晚高峰的商家取消(缺货、爆单后砍单、系统重复派单)率约 3%。
平台因此推了"取消费补偿险":1.0 元一天,当天每遇一次商家取消赔 2.0 元。数字摆在一起很朴素:一天 30 单、取消率 3%,平均被取消 0.90 次,自担白跑 1.44 元;保费只要 1.00 元。1.44 大于 1.00,买。 但"买"这个结论有两处必须抠清楚,否则换个骑手就套错了。
第一处是补偿的口径。 2.0 元的补偿比 1.6 元的实际损失还高。若把补偿当纯收入,买险后每次取消反而赚 0.4 元,日成本 0.64 元;若按保险的损失补偿原则、赔付以填平损失为限,买险后的日成本就是纯保费 1.00 元。两个口径都支持"买",但省下的钱差 0.36 元/天、一年差 131 元。"1.44 大于 1"这句话,严格成立的是后一个口径。 第二处是单量。 保费按天收、是固定的;白跑损失按单量走、是变动的。日单量掉到十几单,"固定成本靠单量摊薄"的逻辑就反过来了。30 单只是本例的刻度,真正要答的是:一天跑到多少单以上,这 1 块钱才不白花。
表 1 案例 096 的参数与派生量(日均口径)
| 符号 | 含义 | 取值 | 来源 |
|---|---|---|---|
| \(n\) | 日均接单量 | 30 | 当日排班 |
| \(p\) | 商家取消率 | 3% | 平台城区统计 |
| \(L\) | 白跑一趟的损失 | 1.6 元 | 8 min 折算 |
| \(c\) | 每次取消的补偿 | 2.0 元 | 保险条款 |
| \(q\) | 保费(按天收) | 1.0 元 | 保险条款 |
为什么值得当成优化问题。 一是每天都在重复:单日只差一两元,一年 526 元对 365 元、差 161 元,是小额高频的复利结构。二是有临界点:买与不买不是信仰,是可算的单量阈值,阈值以下买险纯亏。三是政策会变:补偿从 2 元降到 0,临界线整体右移直到消失,昨天划算的决策今天就错。 Gurobi 怎么解。 只有 1 个 0-1 变量,走标准四步:(1)建模——"买/不买"记为 \(z\),随机取消次数换成期望 \(np\),目标对 \(z\) 线性;(2)预处理——presolve 把目标化成两个常数取小,根节点即定界;(3)分支定界——1 个变量 1 层收敛,NodeCount 通常为 1;(4)参数扫描——\(n\)、\(p\)、\(c\) 各扫一遍,把单点答案变成分区表。单次求解毫秒级,真正的工作量在口径与扫描上。
2 数学模型
设当日接 \(n\) 单、取消率 \(p\)、单次白跑损失 \(L\)、每单补偿 \(c\)、保费 \(q\),决策变量为是否买险:
当日取消次数 \(K\sim\mathrm{Binom}(n,p)\),\(\mathbb{E}[K]=np\)。按题面口径(补偿全额抵扣损失),日成本期望与约束为
式 (2) 是 \(z\) 的线性函数,两个端点为 \(Z(0)=npL\)、\(Z(1)=q+np(L-c)\),最优解必在端点,于是
式 (4) 说明买不买只看期望补偿 \(npc\) 是否超过保费 \(q\),\(L\) 在两边同时出现而被减掉。这正是期望值决策的干净处,也是它的陷阱:它把 \(c>L\) 的超额赔付当成了利润。 口径修正。 保险的损失补偿原则要求赔付不超过实际损失,实际可抵扣额 \(\bar c=\min(c,L)\),修正后
当 \(c\ge L\) 时 \(\bar c=L\)、\(Z(1)=q\):买险后的日成本退化成纯保费,白跑损失被完全填平。此时"\(1.44>1.00\)"才严格成立——左边是自担的期望损失,右边是买断它的价钱。 临界单量:令式 (5) 取等号
即 30 单该买、19 单不该买。风险口径上,无险日成本 \(LK\) 是随机变量,有险(封顶)恒为 \(q\):
式 (7) 是本例真正想说的一句:保险卖的不是期望,是方差——期望只降 0.44 元,标准差从 1.49 元直接归零。模型规模:1 个 0-1 变量、0 条函数约束、2 项目标。它不难,但口径写错就全错:式 (2) 与式 (5) 只差一处 \(\min\),日成本差 0.36 元。
3 Gurobi 求解实现
数据为构造示例:日均 30 单、取消率 3%、单次白跑 1.6 元、补偿 2.0 元、保费 1.0 元,全部取自题面;30 天取消序列用 \(\mathrm{Binom}(30,0.03)\) 抽样生成(种子 96),只用于图 4 的累计曲线,不参与求解。
表 2 基准场景的求解结果(Gurobi,1 个 0-1 变量)
| 口径 | \(z^{*}\) | 日成本期望 / 元 | 相对不买节省 / 元 | 分支节点 |
|---|---|---|---|---|
| 不买(\(z=0\)) | 0 | 1.44 | — | — |
| 买险·补偿封顶 | 1 | 1.00 | 0.44 | 0 |
| 买险·补偿全额(题面原式) | 1 | 0.64 | 0.80 | 0 |
建模只有三行,关键是第一个括号:
g = min(c, L) if cap else c # 实际可抵扣的补偿,别漏封顶
z = m.addVar(vtype=GRB.BINARY, name="z")
m.setObjective(prem * z + n * p * (L - g * z), GRB.MINIMIZE)
(1)\(\min(c,L)\) 必须显式写进代码。\(c>L\) 时若不加封顶,模型会把保险当套利工具——每取消一次净赚 0.4 元,\(z^{*}\) 仍是 1,但报出来的 0.64 元是虚构的,它假设平台肯赔超过损失的钱。(2)期望值只能进目标、不能随意进约束。本例没有与 \(K\) 挂钩的约束,故 \(\mathbb{E}[K]=np\) 是精确等价;一旦加上"被取消三次就收工"这类规则,替换即失效,须改场景模型。 (3)闭式解用来校验求解器,而不是取代它。式 (4) 给了解析判据,脚本同时跑 Gurobi 与闭式解,11×21 的网格上抽 12 点对拍,误差 0.0e+00;加上多档保费、多档赔付上限后闭式解写不出来,模型还在。全部 63 次求解合计 1.4 s,单次 Gurobi Runtime 在微秒级、可忽略,远低于 60 s 预算。
4 结果分析
4.1 把口径拆开

图 1 三种口径下的日成本期望(虚线为 1 元保费线)
图 1 把三种算法摆在一根轴上:不买 1.44 元,即 \(npL=0.90\times1.6\);买险封顶 1.00 元,等于保费,白跑损失被 1.6 元赔付填平;买险全额 0.64 元,因为 2.0 元赔付比 1.6 元损失多 0.4 元,0.90 次共倒赚 0.36 元。题面那句"1.44 大于 1"严格成立的只有中间那根:左边是自担的期望损失,右边是买断它的价钱,两者都是成本、可以直接比。第三根 0.64 元不能拿去跟 1.44 元比——它把保险当成了投资品,而保险的定价逻辑从来不是"赔得比损失多"。结论没错,但省 0.44 元是"填平损失"的省法,省 0.80 元是"超额赔付"的省法,后者是条款红利。

图 2 日均单量与日成本期望(气泡为不买方案的标准差,竖线为临界单量)
图 2 是本案主图。两条直线在 \(n=20.8\) 处交叉:左边不买更便宜,右边买更便宜。19 单时,不买 0.91 元对保费 1.00 元,买险亏 0.09 元;20 单时 0.96 对 1.00、还差 0.04 元,30 单省 0.44 元。气泡大小是不买方案的标准差——30 单时 1.49 元,是均值的 1.04 倍。这条竖线解释了骑手圈那句"跑得少就别买":保费是按天的固定成本,白跑是按单的变动成本,固定成本要靠单量摊薄。
4.2 三个方案与 30 天账本

图 3 三个方案的日成本期望(实心)与标准差(斜纹)
图 3 把期望与标准差并排:三根实心柱差别不大(1.44 / 1.00 / 0.64),三根斜纹柱差出整整一个量级——不买 1.49 元、全额 0.37 元、封顶 0。方案之间真正的分歧不在"平均花多少",而在"每天花多少"。用期望值评价一个消除方差的工具,就像用平均温度评价一件羽绒服。

图 4 30 个运营日的累计成本(阶梯,阴影为差额)
图 4 是模拟的 30 天账本:实际遇到 30 次取消(期望 27 次,抽样略偏多)。不买累计 48.0 元、买险 30.0 元,30 天差 18.0 元;按全额口径差 30.0 元。曲线形状值得看:不买是"平(没遇到)和跳(遇到了)"交替,买险是一条 45 度直线。第 10 天不买已累计 17.6 元、买险 10.0 元,中间隔着 7.6 元;30 天里有 9 天零取消,那些天买险是纯亏 1 元,但只要 30 次取消落在剩下的 21 天里,总账就翻不回来。短期看运气,长期看频率。
4.3 临界单量怎么随参数移动

图 5 取消率对临界单量(左轴)与 30 单时是否买(右轴)的影响
图 5 的主曲线就是式 (6):\(n^{*}=q/(p\bar c)\),与取消率成反比。取消率 1%(淡季、连锁商家)时临界 62.5 单,30 单的骑手不该买(\(30\times0.01\times1.6=0.48\) 元,小于保费 1.00 元);6%(雨季、小作坊)时临界 10.4 单,几乎人人该买。右侧阶梯是 30 单时的选择,在 \(p=2.08\%\) 处从"不买"跳到"买"。

图 6 取消率与日均单量的买险分区(黑线为临界线,星号为本案)
图 6 把式 (6) 摊成分区图:红色区该买、蓝色区不该买,黑色临界线是双曲线 \(np\bar c=q\)。双曲线下方的面积远大于上方——对绝大多数"单量不高、取消率一般"的骑手,不买才对。本案星号(30 单、3%)落在红区但紧贴临界线,日省只有 0.44 元,属"该买但赚得不多"的边缘区。这张图比一句结论有用:"该不该买取消险"没有统一答案,答案是一条线——同一骑手午晚高峰跑 30 单该买,只跑早茶 12 单就不该买。

图 7 每次取消的补偿额对临界单量(左轴)与日节省(右轴)的影响
图 7 换第三个维度:补偿 \(c\)。三条曲线对应三种取消率,形状都是 \(1/c\) 的双曲线,在 \(c=1.6\) 处折一下——式 (5) 的 \(\bar c=\min(c,L)\) 到顶了,补偿再高也不再抬高临界单量。\(c=0\)(平台取消单独补偿、只剩保费)时临界发散:任何单量都不该买,这正是政策变化最危险的地方。右侧紫色折线是 30 单时日节省,从 \(-1.0\) 元升到 0.44 元后走平,说明超过 1.6 元的补偿对决策毫无价值,不必为"高赔付版本"多付保费。
4.4 买的是确定性

图 8 日成本的期望—标准差平面(灰区期望劣于不买,虚线连前沿)
图 8 最该看。横轴标准差、纵轴期望,三个方案是三点:不买(1.49, 1.44)、封顶(0, 1.00)、全额(0.37, 0.64)。封顶同时压低期望与方差,直接支配不买——相当于把点从右下角搬到横轴原点,期望降 0.44 元、标准差降 1.49 元,这不是权衡、是纯改进。真正的权衡只在封顶与全额之间:全额再省 0.36 元期望,代价是 0.37 元标准差。按 \(\lambda=0.5\) 折成确定性等价 \(\mathbb{E}+\lambda\sigma^{2}\):不买 2.56、封顶 1.00、全额 0.71,全额仍略胜;要让封顶反超,风险厌恶系数得高过 2.58。买险先解决「该不该买」(封顶支配不买),再解决「买多好」(封顶与全额之间按风险偏好挑)。

图 9 日成本的概率分布与累积分布(不买离散多峰,买险单点)
图 9 是零膨胀分布的标准长相:不买时 40% 的日子一分不花,37% 花 1.6 元,17% 花 3.2 元,尾巴拖到 9.6 元。买险后全部概率质量集中到 1.0 元。两条累积曲线在 1.0 元处交叉:约 40% 的日子不买更省,其余 60% 买险更省——"大概率小赚、小概率大亏"的准确画像。CV 从 1.04 降到 0,不买的 CV 大于 1,意味着波动比均值还大。
4.5 钱去哪了

图 10 三个方案的成本分解(保费 / 净白跑 / 超额补偿)
图 10 把 1.44 元拆成三块:不买全是净白跑;封顶是保费 1.00 元加净白跑 0;全额是保费 1.00 元减超额补偿 0.36 元。从"不买"到"封顶"的边际分解是 \(+1.00\)(保费)\(-1.44\)(白跑消失)\(=-0.44\) 元。 符号很说明问题:保费是唯一确定的支出,白跑是唯一不确定的支出;买险做的事,是把均值 1.44、标准差 1.49 的随机项,换成均值 1.00、标准差 0 的确定项。省下的 0.44 元是这笔交换的手续费返还,真正的商品是那个 0。 决策口径汇总:日均 30 单、取消率 3% 时买,日省 0.44 元、月省 13.2 元、年省 161 元;临界单量 20.8 单,低于它别买。
5 结论
(1)买,但省的是 0.44 元而不是 0.80 元。 按损失补偿原则(赔付不超过 1.6 元损失),买险把日成本从 1.44 元压到 1.00 元,日省 0.44 元、年省 161 元。题面"1.44 大于 1"成立,但它成立的口径是"补偿填平损失":左边是自担的期望损失,右边是买断它的价钱。按题面原式把 2.0 元全额当收入得 0.64 元、省 0.80 元,数字更大,但那是条款红利、不是保险逻辑,不能当主结论。
(2)临界单量 20.8 单,这才是本案真正的结论。 保费按天收(固定)、白跑按单量走(变动),\(n^{*}=q/(p\bar c)=1.0/(0.03\times1.6)=20.83\)。30 单买险划算(1.44 对 1.00);19 单不买才划算(0.91 对 1.00,买险亏 0.09 元)。"该不该买"没有统一答案,答案是一条双曲线(图 6):同一份保险,午晚高峰该买、只跑早茶不该买。
(3)买险买的是确定性,不是期望。 期望只降 0.44 元(降幅 31%),标准差从 1.49 元降到 0(降幅 100%),CV 从 1.04 降到 0。不买时 40% 的日子零成本、其余日子跳一下,这种结构用期望值评价会严重低估保险的价值。
(4)灵敏度:临界线由三个参数共同决定,任一条变动都可能翻转结论。 取消率 1% 时 \(n^{*}=62.5\)(30 单不该买),6% 时 \(n^{*}=10.4\)(人人该买);补偿从 2 元降到 0,\(n^{*}\) 发散(任何单量都不该买);补偿超过 1.6 元的部分对临界线没有贡献,不必为"高赔付版本"多付保费。条款变动时,先算临界单量,再决定续不续。
(5)建模层面:1 个变量也能翻车,翻在口径上。 模型只有 1 个 0-1 变量、0 条函数约束、毫秒级求解,63 次求解合计 1.4 s。风险不在求解,而在忘掉 \(\min(c,L)\)——式 (2) 与式 (5) 只差一个封顶,日成本差 0.36 元、年差 131 元。先定口径、再写目标、最后交给求解器,这对"简单到可以口算"的模型尤其重要。
参考文献
[1] Gurobi Optimization LLC. Gurobi Optimizer Reference Manual[Z]. 2024.
[2] Kellerer H, Pferschy U, Pisinger D. Knapsack Problems[M]. Berlin: Springer, 2004.
[3] Martello S, Toth P. Knapsack Problems: Algorithms and Computer Implementations[M]. Chichester: John Wiley & Sons, 1990.
[4] 司守奎, 孙玺菁. 数学建模算法与应用[M]. 3 版. 北京: 国防工业出版社, 2021.
复现方式:python batch_096.py;数据与结果见同目录 data_096.csv / results_096.json,图见 figs/

浙公网安备 33010602011771号