开始前,会这些就够了
- 知道平均值与中位数的区别
- 能读分段函数和排序
- 先读 预测没变,只把米换成厘米,损失为什么涨了 4.605?:按该文准备相关概念。
- 先读 区间写着九成覆盖,为什么某一类样本一次也没包住?:按该文准备相关概念。
预测需要多少份资源,少估一份可能比多估一份更昂贵。若仍然只用对称误差,你实际上给两种错误设了同一个价格。Pinball 损失允许低估与高估使用不同的线性代价。
它常被概括为“预测一个分位数”。但有限样本下,最佳答案可能是一整段区间。本文让四个观测共用一个常数预测,直接看清这个边界。
把例子带到自己的电脑上
下载完整练习包
需要 Python 3.10 或更新版本,无第三方依赖;制作时实测 Windows / Python 3.14.0。使用标准库,不需要安装第三方包。下载 ZIP 后选择“全部提取”,进入能看到 README.md 的文件夹。
下载 ZIP · 5 个文件包里有什么
- pinball_intervals.py:完整可运行示例
- README.md:运行说明与独立练习
- observed.stdout.txt:本次实际输出
- verification.json:源码和产物验证记录
- SHA256SUMS.txt:内容摘要
在这个文件夹打开 PowerShell,逐行运行
python --version
python -B pinball_intervals.py解压到独立练习文件夹,在含 pinball_intervals.py 的目录打开终端运行。已运行两组固定样本的精确分数最优区间、424 个网格点、累计比例及代价比例检查;未拟合带特征模型、调用 sklearn/statsmodels 或测量未来覆盖率。
找不到命令或文件时,先按 README 检查环境和所在目录。文中标出的阅读时间只估算文章篇幅,安装环境和动手练习可按自己的节奏进行。
同样差 1,低估和高估各扣多少?
四次观察共用一个预测值 q。低估时,每差 1 扣 τ;高估时,每差 1 扣 1 − τ。调大 τ,会让低估更贵。
蓝线表示平均损失,绿色标出最优集合,橙点表示当前预测。
当前平均损失:1.125。最小平均损失:1.125。
取得最小值的 q:[2, 4] 整个闭区间。当前预测就在最优集合里。
底部是一段平线,说明最优预测可以不唯一;它不需要恰好等于某个观察值。
查看四次误差怎样计费
| 观察值 | 预测方向 | 本项损失 |
|---|---|---|
| 1 | 高估 | 1.000 |
| 2 | 高估 | 0.500 |
| 4 | 低估 | 0.500 |
| 8 | 低估 | 2.500 |
这是四个固定样本、等权重、共用常数预测的经验损失;没有训练条件分位数模型,也不承诺新数据覆盖率。τ = 50% 时,这里的损失是绝对误差的一半,两者的最优集合相同。
先约定什么叫低估
令真实值为 y,预测为 q,误差 u=y−q。u>0 表示低估,u<0 表示高估。给定 0<τ<1,单样本损失 ρτ(u)=τu(u≥0),或 (τ−1)u(u<0)。第二段的两个因子都是负数,所以损失仍然非负。
也可以写成 τ·max(y−q,0)+(1−τ)·max(q−y,0)。τ 是低估方向的每单位代价,1−τ 是高估方向的每单位代价;多个样本的损失取平均。
如果低估一单位损失 3,高估一单位损失 1,取 τ=3/(3+1)=0.75。实际代价等于 Pinball 损失乘 4,最优预测集合不变。这只适用于这里的线性、固定单位代价,其他业务成本需要重新建模。
为什么最优答案可能是一整段
取排序数据 [1,2,4,8],所有观测共用预测 q。τ=0.5 时,对 q=2、3、4,平均 Pinball 损失都为 1.125;整个闭区间 [2,4] 都最优。按照本文的标准定义,τ=0.5 的 Pinball 数值是 MAE 的一半,最优集合相同。
在 q 严格位于两个相邻数据之间时,平均损失对 q 的斜率为“低于 q 的样本比例 − τ”。例如 q∈(2,4) 时,四个样本里有两个低于 q,斜率为 2/4−0.5=0。因此移动 q 既增加一部分高估损失,又减少同样多的低估损失,恰好抵消。
对同一组数据,τ=0.25 的最优区间为 [1,2];τ=0.75 为 [4,8];τ=0.9 只有 q=8。分位点计算库可能按某种插值规则返回一个代表值,但那不等于该损失的所有最优解只有那一点。
用左右累计比例处理重复值
更完整的最优条件是 Fₙ(q−)≤τ≤Fₙ(q)。左边 Fₙ(q−) 表示严格小于 q 的样本比例,右边 Fₙ(q) 表示小于等于 q 的比例;两者在有重复值的位置会跳开。
对 [0,0,0,10],τ=0.5 的最优值只有 0;τ=0.75 时,整个 [0,10] 都最优。取 q=0 时左右比例为 0 与 0.75;取 0<q<10 时二者都为 0.75;取 q=10 时为 0.75 与 1,全部满足条件。
计算方法是:把 n 个样本排序,若 nτ 是整数 k,则最优区间为第 k 与第 k+1 个排序值之间,包含两端;否则唯一的排序值位置为向上取整的 nτ。这里位置从 1 开始,重复值可让区间缩成一点;程序使用精确分数避免把整数判断交给浮点误差。
一个常数目标,不是未来覆盖承诺
本例所有样本共用 q,因此得到经验分布的分位数最优集合。加入特征后,模型通常学习随特征改变的条件分位数;模型容量、正则化、样本数量都会影响实际结果。
分别拟合上下分位数,也不自动得到经过验证的未来覆盖率。共形校准、独立验证与分布变化是另外的问题。这里的 75% 是损失不对称参数,不能直接当成对下一批数据已经成立的概率保证。
程序在两组数据、四个 τ、53 个候选 q 上检查共 424 个点,核对损失最小集合、左右累计条件和 τ=0.5 的比例关系;另检查三比一单位成本换算。练习只给任务与检查要求,不预先给改动后的答案。
运行完整实验并检查报告
保存为 pinball_intervals.py,运行 python -B pinball_intervals.py。预期输出来自本次实际运行;完整结果写入 report.json。
已运行两组固定样本的精确分数最优区间、424 个网格点、累计比例及代价比例检查;未拟合带特征模型、调用 sklearn/statsmodels 或测量未来覆盖率。
展开收起代码 · 小实验
长行可在代码区域内左右滚动,按 Tab 可把焦点移入代码区。
"""Exact empirical pinball minimizer intervals with ties."""
from fractions import Fraction as F
import json
from pathlib import Path
def loss(values,q,tau):
if not values or not 0<tau<1:
raise ValueError('nonempty sample and 0<tau<1 required')
return sum(tau*max(y-q,0)+(1-tau)*max(q-y,0) for y in values)/len(values)
def minimizers(values,tau):
if not values or not 0<tau<1:
raise ValueError('nonempty sample and 0<tau<1 required')
ys=sorted(values); rank=len(ys)*tau
if rank.denominator==1:
k=int(rank)
return ys[k-1],ys[k]
k=(rank.numerator+rank.denominator-1)//rank.denominator
return ys[k-1],ys[k-1]
def cdf_bracket(values,q):
n=len(values)
return F(sum(y<q for y in values),n),F(sum(y<=q for y in values),n)
def main():
data=[F(1),F(2),F(4),F(8)]
tied=[F(0),F(0),F(0),F(10)]
rows=[]
for label,values in [('distinct',data),('ties',tied)]:
for tau in [F(1,4),F(1,2),F(3,4),F(9,10)]:
lo,hi=minimizers(values,tau)
optimum=loss(values,lo,tau)
assert loss(values,hi,tau)==loss(values,(lo+hi)/2,tau)==optimum
for q in [F(k,4) for k in range(-4,49)]:
got=loss(values,q,tau)
below,at=cdf_bracket(values,q)
assert got>=optimum
assert (got==optimum)==(lo<=q<=hi)==(below<=tau<=at)
if tau==F(1,2):
mae=sum(abs(y-q) for y in values)/len(values)
assert got==mae/2
rows.append(dict(dataset=label,tau=str(tau),interval=[str(lo),str(hi)],minimum=str(optimum)))
assert minimizers(data,F(1,2))==(F(2),F(4))
assert minimizers(tied,F(3,4))==(F(0),F(10))
# Underprediction cost 3 and overprediction cost 1 give tau=3/4.
q=F(5); tau=F(3,4)
costs=sum(3*max(y-q,0)+max(q-y,0) for y in data)/len(data)
assert costs==4*loss(data,q,tau)
rejected=0
for values,tau in [([],F(1,2)),(data,F(0)),(data,F(1)),(data,F(-1))]:
try: minimizers(values,tau)
except ValueError: rejected+=1
assert rejected==4
report=dict(datasets=dict(distinct=list(map(str,data)),ties=list(map(str,tied))),results=rows,
grid_checks=2*4*53,cost_ratio=[3,1],invalid_rejections=rejected,checks_passed=True)
Path('report.json').write_text(json.dumps(report,indent=2)+'\n',encoding='utf-8')
for row in rows:
print(f"{row['dataset']} tau={row['tau']}: minimizers=[{','.join(row['interval'])}], loss={row['minimum']}")
print('tau=1/2 pinball=MAE/2; CDF bracket and 424 grid checks=PASS')
print('report.json written')
if __name__=='__main__': main()
怎样运行:在独立练习文件夹中执行 python -B pinball_intervals.py。2026-10-18 已在 Windows、Python 3.14.0 运行此份源码并通过自带检查。已运行两组固定样本的精确分数最优区间、424 个网格点、累计比例及代价比例检查;未拟合带特征模型、调用 sklearn/statsmodels 或测量未来覆盖率。
运行后对照结果
distinct tau=1/4: minimizers=[1,2], loss=11/16
distinct tau=1/2: minimizers=[2,4], loss=9/8
distinct tau=3/4: minimizers=[4,8], loss=17/16
distinct tau=9/10: minimizers=[8,8], loss=17/40
ties tau=1/4: minimizers=[0,0], loss=5/8
ties tau=1/2: minimizers=[0,0], loss=5/4
ties tau=3/4: minimizers=[0,10], loss=15/8
ties tau=9/10: minimizers=[10,10], loss=3/4
tau=1/2 pinball=MAE/2; CDF bracket and 424 grid checks=PASS
report.json written记住这些要点
- 低估与高估的单位价格决定 τ。
- τ=0.5 的 Pinball 是 MAE 的一半。
- 有限样本的分位数最优解可能是整个闭区间。
- 经验最优与未来覆盖保证是不同结论。
别把例子用过头
- 把 y−q 写反后仍按原解释设置 τ。
- 看到库返回一个分位数便宣称损失只有一个最优点。
- 把训练集分位数比例直接当成新数据覆盖率。
自己试一小步
把最大值 8 改成 80,哪些 τ 的最优区间会改变?
- 不运行程序,先按 nτ 与排序位置写出四个最优集合。
- 比较 τ=0.5 与平方损失的最佳常数预测。
- 再用 [0,0,10,10] 检查重复值处的左右累计条件。
做到这些,就算完成
- 返回完整最优区间,包含两端。
- 说明采用的样本权重及 τ 范围。
- 把训练样本计算与未来预测保证分开。
查原始资料
想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。
- Pinball loss 用户指南 (新标签页)↗
非对称线性损失及 τ=0.5 是 MAE 一半
- Quantile regression 示例 (新标签页)↗
平均值、中位数与目标损失的区别
- Quantile regression: Least Absolute Deviation (新标签页)↗
q=0.5 的最小绝对偏差及条件分位数模型