案例092 投诉率红线
案例092 投诉率红线
摘要:平台规定投诉率超过 0.5% 就限流,骑手日均 32.55 单的能力上限下投诉率只有 0.165%。把「投诉率」写成 \(pn\le\theta n\) 后约去 \(n\) 得 \(p\le\theta\),再代入疲劳关系 \(p=p_0+kn\),解出 \(n\le200\) 单——这条看似最要紧的红线,在 32.55 单处留了 3.0 倍余量,是彻底的冗余约束:Gurobi 给它的影子价格恰为 0,删掉它最优解一动不动。真正卡住单量的是 10.5 h × 3.1 单/h = 32.55 单的配送能力。但把红线从「比率」换成「次数」(日投诉 ≥1 单的概率不超过 5%),同一个 0.5% 精神立刻变成真约束:\(n^*\) 从 32.55 降到 31.46 单,收入少 6.11 元/天。阈值也给出:比率红线低于 0.165%、次数红线低于 5.24% 才有约束力。
关键词:冗余约束;比率约束化简;影子价格;IIS 诊断;二项尾概率
1 问题提出
1.1 问题是什么
平台的限流规则写在合同里:日投诉率超过 0.5%,次日进限流池。骑手这一天的账很简单——每单净赚 5.6 元,多跑一单多赚 5.6 元,所以想跑得越多越好;但跑得越多越累,越累越容易出岔子,投诉概率随单量上升:
题面给的日均 55 单要按 3.1 单/h 折算需要 17.7 小时连续作业,已经超出单人单平台的体力可行域;本案取 10.5 小时有效在线,能力上限 \(n_{cap}=10.5\times3.1=32.55\) 单。这条能力上限是后来全部结论的分水岭。
表 1 参数与派生临界值
| 项目 | 符号 | 取值 | 含义 | |---|---|---|---| | 基准投诉概率 | $p_0$ | 0.001 | 单量趋于 0 时的投诉率 | | 疲劳斜率 | $k$ | 2.0e-05 | 每多一单,投诉概率上升量 | | 投诉率红线 | $\theta$ | 0.5% | 平台限流门槛 | | 次数红线 | $\alpha$ | 5% | 日投诉≥1 单的概率上限 | | 单均净收益 | $b$ | 5.6 元 | 目标函数系数 | | 能力上限 | $n_{cap}$ | 32.55 单 | 10.5 h × 3.1 单/h | | 比率失效阈值 | $n_{cut}$ | 200 单 | 红线开始起作用的最小单量 | | 临界红线 | $\theta_{crit}$ | 0.1651% | 低于此值比率约束才有约束力 | | 临界容忍度 | $\alpha_{crit}$ | 5.2364% | 高于此值次数约束才冗余 |1.2 为什么要优化
其一,红线是不是真约束,凭感觉一定判错。 0.5% 听上去离得很近,但把它和 \(p(n)\) 的斜率放在一起算,交点落在 200 单,是能力上限的 6.1 倍。其二,口径决定结论。「投诉率 ≤ 0.5%」和「一天不超过 0 单投诉」在口语里是同一句话,在数学上是两个完全不同的可行域——前者是均值约束,后者是分位数约束,后者含 \(n\) 次幂。其三,约束冗余的判别要能自动化。 170 个案例里有一半约束是白写的,靠肉眼挑不出来,需要影子价格和 IIS 这类工具做体检。
1.3 Gurobi 如何求解
三步。第一步把 \(pn\le\theta n\) 化简成线性 \(p\le\theta\),建两变量 LP 求解,读约束的影子价格——影子价格为 0 就是冗余的机器判据。第二步用字面双线性形式 \(pn\le\theta n\)(NonConvex=2)独立求解一遍,验证化简没有改变最优值;再把能力上限人为放到 250 单,看模型自己停在哪。第三步做 IIS:把 \(n\ge201\) 写进约束,模型必不可行,computeIIS() 会指出到底是哪几条约束在打架。次数口径不做线性化,直接对单调方程二分。
2 数学模型
2.1 符号说明
日单量 \(n\ge0\);单均投诉概率 \(p\ge0\);基准概率 \(p_0=0.001\);疲劳斜率 \(k=2.0e-05\);投诉率红线 \(\theta=0.005\);次数红线 \(\alpha=0.05\);单均净收益 \(b=5.6\) 元;能力上限 \(n_{cap}=32.55\) 单;限流损失 \(\Lambda=218.74\) 元。
2.2 目标函数
一天的收入与单量成正比,没有固定成本,也没有规模报酬:
2.3 约束条件
投诉率的定义式与平台红线分别是
式 (4) 是本案例的全部戏肉。\(n>0\) 时两边同除 \(n\)(\(n=0\) 时式 (4) 自动成立),得
再补上能力约束:
式 (7) 就是本案的判决书:200 与 32.55 差了一个数量级,红线根本没参与决策。式 (4) 的右端写成 \(\theta n\) 不是文字游戏——它把「率」的定义原样搬进了约束,正因为右边也跟着 \(n\) 长,两边才约得掉;若写成 \(pn\le\theta\)(把分子当绝对次数),约束就变成 \(n(p_0+kn)\le\theta\),那是另一个模型,见 2.4。
2.4 次数口径:同一句红线的另一种数学
「日均 55 单,最多容忍 0 单投诉」在概率意义上是至少一单投诉的概率不超过 \(\alpha\):
式 (8) 左端对 \(n\) 单调递增(\(p\) 本身也在涨),所以 \(n^{*}\) 是方程 \(1-(1-p_0-kn)^n=\alpha\) 的唯一根,用二分求得 \(n^{*}_{cnt}=31.46\) 单。它和式 (5) 的 200 单没有任何关系:一个是「平均每单的投诉率」,一个是「一天里一次都不许出事的概率」,\(n\) 在后者里是指数。两者在同一组参数下的差:
2.5 两条红线的临界值
比率红线什么时候才开始卡人?令式 (5) 的右端等于能力上限:
次数红线同理,令 \(n=n_{cap}\) 代入式 (8):\(\alpha_{crit}=5.2364\%\)。这两个数字把参数空间切成「有约束力/冗余」两半:\(\theta\ge0.165\%\) 时比率约束是废纸,\(\alpha\ge5.24\%\) 时次数约束也是废纸。本案 \(\theta=0.5\%\) 落在废纸区的第三倍处,而 \(\alpha=5\%\) 只比临界值低 0.24 个百分点——同样的 5% 精神,一个彻底冗余,一个勉强生效。
3 Gurobi 求解实现
3.1 建模要点
n = m.addVar(lb=0.0, ub=NCAP, name="n"); p = m.addVar(lb=0.0, ub=1.0, name="p")
m.addConstr(p == P0 + K * n, name="c_def")
c_ratio = m.addConstr(p <= THETA, name="c_ratio") # 式(4) 化简后的形式
m.setObjective(5.6 * n, GRB.MAXIMIZE); m.optimize()
print(c_ratio.Pi) # 0.0 → 冗余
一条实现细节:用 Pi 而不是肉眼判断冗余。Gurobi 对松弛约束返回的影子价格是精确的 0(本案打印 0),把它和「删掉约束再解一次」的结果对照,两条证据互相印证。若把 \(\theta\) 调到 0.165% 以下,Pi 立刻跳到 \(b/k=280000\)——每放宽一个单位的投诉率,日收益涨 280000 元,这个数字大到荒谬,恰好说明「投诉率」这个量纲本身没有经济含义,有用的只是它对应的单量。
3.2 求解结果
表 2 三种口径的最优解(同一组参数)
| 口径 | 约束写法 | n* / 单 | 投诉率 | 日收益 / 元 | 影子价格 | 是否紧 | |---|---|---|---|---|---|---| | 比率口径 | $p\le\theta$ | 32.55 | 0.165% | 182.28 | 0 | 否(能力先卡住) | | 次数口径 | $1-(1-p)^n\le\alpha$ | 31.46 | 0.163% | 176.17 | — | 是(相对能力) | | 去掉红线 | 仅 $n\le n_{cap}$ | 32.55 | 0.165% | 182.28 | — | — |三行数字里,第一行和第三行完全一致(182.28 元),这就是冗余的算术证明;第二行少了 6.11 元,是次数口径的代价。字面双线性模型(NonConvex=2)在能力放到 250 单时自己停在 \(n=200.00\),与式 (5) 的 200 吻合到小数点后两位,说明化简没有偷换问题。IIS 实验:\(n\ge201\) 时模型不可行,computeIIS() 给出 \(\{c_def、c_ratio、c_min\}\) 三条约束——红线只有在 201 这个本来就不可能达到的单量上才会咬人;把红线删掉,\(n\ge201\) 立刻可行(最优 1000.00 单)。
4 结果分析
4.1 结构:一条斜率极浅的直线与一条够不着的红线

图 1 投诉概率随单量线性上升(棒棒糖为 20 单步长)与 0.5% 红线:交点在 200 单
图 1 把式 (1) 画成棒棒糖:20 单一步,概率从 0.1% 爬到 0.5%。红线 0.5% 横在上面,两者在 200 单处才相交——**这条红线在图上离骑手的活动范围隔了六倍**。本案 32.55 单处概率 0.165%,红线余量 3.03 倍。斜率只有 2.0e-05,意味着多跑一单只把概率推高 0.002 个百分点,**疲劳在这个参数下几乎不构成风险**——这是题面数据本身的性质,模型只是把它翻译出来。
图 2 单量—投诉率的散点气泡(气泡面积∝日收益):达标区间(浅绿)与红线失效阈值
图 2 换视角:横轴单量、纵轴投诉率、气泡面积是日收益。所有点都躺在一条直线上,收益随气泡膨胀,风险随纵坐标上升,**但纵坐标的上升速度远慢于横轴**——跑满 200 单,投诉率才爬到红线。图的右下角是本案的可行区(32.55 单以内、0.5% 以下),左上角那块浅红区域(比率红线不可行区)**根本不在骑手的可达范围内**。这也是全案的教学点:**判断约束松紧必须把约束和可行域画在同一张图上**,单看系数大小毫无意义。4.2 三口径对比与 IIS 证据

图 3 三种口径的最优单量(柱)与日收益(点线):比率口径与「只受能力」完全重合
图 3 的三根柱子是表 2 的图形版:比率口径 32.55 单、次数口径 31.46 单、去掉红线 32.55 单。**第一根和第三根等高**,这是冗余最直观的呈现;第二根矮了 1.09 单,日收益从 182.28 掉到 176.17。值得注意的是次数口径的差距并不大(3.4%),但它**性质完全不同**:比率口径下红线的影子价格是 0,次数口径下它是真在拉低单量的那只手。
图 4 单量累积下的期望投诉数(左轴)与累计收益(右轴):投诉数增长快于收益
图 4 是累积视角。左轴是 $\sum_{i=1}^{n}p(i)$,即一天里期望收到的投诉条数,右轴是累计收益。两条线都随 $n$ 上升,但一个是二次($p$ 随 $n$ 涨,求和又是 $n$ 项),一个是线性。跑到 32.55 单只积累 0.043 条期望投诉——**一天平均 0.043 条,这就是「0.5% 投诉率」的真实体感**:绝大多数日子一条投诉都没有,红线像一个与自己无关的告示。可一旦出一次,就是 219 元量级的限流损失。**期望值小、尾部重**,正是必须换用次数口径的原因。4.3 灵敏度:红线在哪儿才有牙

图 5 红线比例对最优单量的影响(左轴,三条斜率)与相对收入损失(右轴)
图 5 的左轴是 $n^{*}(\theta)=\min\{n_{cap},(\theta-p_0)/k\}$,三条斜率各一条线。所有曲线在 $\theta\ge0.165\%$ 处压成一条水平线 $n^{*}=32.55$——**这就是「约束无效区」,红线怎么改都不影响决策**;低于这个阈值后曲线斜着掉下来,斜率 -50 单/百分点($1/k$ 的量级)。本案 $\theta=0.5\%$ 稳稳坐在水平段上。右轴是相对收入损失,同样在 0.165% 处从 0 起跳。**这张图给出的操作性结论是**:平台把红线从 0.5% 收紧到 0.2%,对本案毫无影响(仍然是 32.55 单);只有收到 0.165% 以下,才会真正压单量。
图 6 红线比例 × 疲劳斜率的最优单量热图:虚线是「约束开始起作用」的分界
图 6 是二维分区,横轴是红线比例、纵轴是疲劳斜率 $k$,填色是最优单量,虚线是 $\theta_{crit}(k)=p_0+k\,n_{cap}$ 的分界。虚线右上方整块是 32.55 单的深色区(约束冗余),左下角颜色迅速变浅(约束生效)。**斜率 $k$ 越大,分界线越往右上跑**:疲劳越显著,红线能容忍的比例也越高——因为同样单量下投诉率更高,平台容忍度相对变宽。星标 (0.5%, 2e-5) 深深地落在冗余区。4.4 第三维:换成次数口径

图 7 次数红线 α 对最优单量的影响(左轴)与距能力上限的缺口(右轴)
图 7 把红线换成次数口径,横轴是容忍度 $\alpha$。三条曲线在 $\alpha=5.24\%$ 右侧全部并到能力上限 32.55 单,左侧陡降:$\alpha=5\%$ 时 31.46 单,$1\%$ 时约 8.6 单,$0.5\%$ 时只剩 4.6 单。**同一句「不许有投诉」,换个口径就从「永远满足」变成「每天少跑一单」再变成「只能跑四单」。** 右轴是距能力上限的缺口,形状与左轴镜像。
图 8 可行前沿与两块不可行阴影:前沿在 32.55 单被截断,红带要到 200 单才够得着
图 8 把两块不可行区叠在可行前沿上:竖条纹是「能力不可行」($n>32.55$),浅红带是「比率红线不可行」($p>0.5\%$)。前沿在 32.55 单处就被竖条纹截断,而要爬进红色带得跑到 200 单——**两者在横轴上隔着 167 单,这就是冗余的几何形状**。两颗星(后者是菱形)分别是能力上限解(32.55)和次数口径解(31.46),后者只左移 1.09 单,却把 $P(K\ge1)$ 从 5.24% 压到 5%。4.5 分布与分解

图 9 投诉次数分布(对数轴柱)与累计概率(点线,右轴):31 单与 32 单的分界
图 9 是分布的视角(对数纵轴)。31 单时 $P(K\ge1)=4.90\%$,32 单时 5.12%——**跨过 5% 只用多接一单**。这就是次数口径的全部张力:它不是一个可以四舍五入的约束,31 与 32 之间没有中间地带。右轴累计概率在 $k=0$ 处正好是 $1-P(K\ge1)$,两条线在 95% 附近的相对位置决定了谁合规。若按整数排班,**次数红线的整数解是 31 单**,比连续解 31.46 还要保守半单。
图 10 毛收益、期望限流罚损与净收益的分解:超线的 6 元收益换不回 11 元期望罚损
图 10 把收益与风险拆开:柱子的总高是毛收益 $5.6n$,红色部分是期望限流罚损 $P(K\ge1)\cdot\Lambda$($\Lambda=218.74$ 元 = 限流 3 天 × 降 40% × 32.55 单 × 5.6 元),蓝色是净收益。32 单比 31 单多赚 5.60 元毛收益,但期望罚损多出 0.47 元——**净收益反而少 5.13 元**。整段 $n\in[28,34]$ 上净收益是单调下降的,只在 31.5 单处有拐点。**「多跑一单多赚 5.6 元」这句话在红线附近是假的**:边际收益 5.6 元,边际期望罚损 $0.48$ 元,后者已经开始反超。5 结论
(1)比率红线在本案是彻底的冗余约束。\(pn\le\theta n\) 约去 \(n\) 得 \(p\le\theta\),再代入 \(p=p_0+kn\) 得 \(n\le200\) 单,是能力上限 32.55 单的 6.1 倍;影子价格 0、删掉约束最优解不变、IIS 只在 \(n\ge201\) 时报警,三条证据同向。
(2)真正卡住单量的是配送能力,不是合规。10.5 h × 3.1 单/h = 32.55 单,最优收入 182.28 元/天。把工时当成唯一瓶颈,模型的结论才与骑手的实际感受对得上——他担心的是跑不完,不是被限流。
(3)口径一换,结论全变。「投诉率 ≤ 0.5%」是均值约束,「日投诉 ≥1 单概率 ≤ 5%」是分位数约束,后者含 \(n\) 次幂。同一组参数下 \(n^{*}\) 从 32.55 掉到 31.46(整数 31),代价 6.11 元/天、183 元/月。这是本案例相对原题的主要增量:冗余与紧,只差一个「率」字的解释。
(4)两条红线各有明确的失效阈值:比率红线 \(\theta_{crit}=p_0+k n_{cap}=0.165\%\),次数红线 \(\alpha_{crit}=5.24\%\)。本题的 0.5% 是阈值的 3.0 倍(彻底冗余),5% 只比阈值低 0.24 个百分点(勉强生效)。平台若真想用红线管住单量,应当直接规定单量上限,而不是规定一个随单量自动放大的比率。
(5)期望值小、尾部重,是这类约束的通病。一天期望投诉 0.043 条,但一次限流罚 219 元;净收益在 31.5 单处见顶。模型给出的排班答案是「31 单/天」——比能力上限少 1.6 单,比合规上限多不出任何东西,这是一个用 6 元钱买 5% 尾部风险的干净交易。
参考文献
[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.

浙公网安备 33010602011771号