TATECHATLAS
◎ 简体中文
数学与模型 / 指南

scikit-learn 中的分位数回归与 Pinball Loss

本文介绍了如何在 scikit-learn 中实现、评估和调优分位数回归模型。重点讲解了如何使用 pinball loss 损失函数以及 D² 技能评分,并提供了在交叉验证和超参数调优中正确使用这些指标的详细指南。

本文内容

要在 scikit-learn 中执行分位数回归,您必须通过选择相同的目标分位数 (alpha) 来使模型的优化目标与评估指标保持一致。您可以使用支持分位数损失的回归器,例如设置 loss='quantile' 并通过 'quantile' 参数指定目标的 HistGradientBoostingRegressor。在评估方面,请使用带有相应 'alpha' 参数的 mean_pinball_loss。要在交叉验证或超参数调优中使用这些指标,请使用 make_scorer 对其进行封装,并确保设置 greater_is_better=False,因为 pinball loss 是一个需要被最小化的值。为了评估模型相对于基准线的技能水平,请使用 d2_pinball_score,它将 R² 的概念推广到了分位数。在处理多目标任务时,请使用 multioutput 参数来定义如何聚合各个输出的误差。

为您的决策定义目标分位数

在训练之前,您必须确定业务或科学目标所需的特定分位数 (alpha)。与针对期望值的均值回归不同,分位数回归针对的是条件分布中的一个特定点。例如,网络提供商可能希望预测连接中断的第 99 百分位数,以保证服务可靠性。一旦选择了这个 alpha 值,它在训练和评估阶段都必须保持一致,以确保模型针对正确的函数进行优化。

在进行 GridSearchCV 超参数调优时,请务必使用负的 pinball loss(通过 make_scorer 实现),以确保优化器通过最大化分数来正确识别最佳模型。

选择一个最小化 pinball loss 的模型

在 scikit-learn 中,您需要选择一个支持分位数损失的估计器。例如,HistGradientBoostingRegressor 可以配置为 loss='quantile' 并指定特定的 'quantile' 参数。其他选项还包括 QuantileRegressor。模型将尝试最小化 pinball loss,以找到满足所选分位数水平的值。

from sklearn.ensemble import HistGradientBoostingRegressor
import numpy as np

X = np.random.rand(100, 1)
y = 2 * X.ravel() + np.random.normal(0, 0.5, 100)

# Target the 95th percentile
model = HistGradientBoostingRegressor(loss='quantile', quantile=0.95)
model.fit(X, y)

使用相同的 alpha 进行 mean_pinball_loss 评估

为了衡量模型的表现,请使用 mean_pinball_loss 函数。关键的一点是,传递给此函数的 alpha 参数必须与模型训练期间针对的分位数完全相同。如果您训练的是 0.95 分位数,但使用 0.50 进行评估,那么生成的误差指标对于您的特定任务来说将毫无意义。

from sklearn.metrics import mean_pinball_loss

y_pred = model.predict(X)
loss = mean_pinball_loss(y, y_pred, alpha=0.95)
print(f'Pinball Loss: {loss}')

为调优和验证创建自定义评分器

当使用交叉验证或 GridSearchCV 时,您不能直接传递 mean_pinball_loss,因为它是一个损失值(需要最小化),而不是一个分数(需要最大化)。您必须使用 make_scorer 对其进行封装。由于 scikit-learn 的优化逻辑期望值越高越好,因此您必须设置 greater_is_better=False。这会告诉评分器在内部对损失值取负号。

from sklearn.metrics import make_scorer
from sklearn.model_selection import cross_val_score

# Create a scorer for the 95th percentile
scorer = make_scorer(mean_pinball_loss, alpha=0.95, greater_is_better=False)

# Use in cross-validation
scores = cross_val_score(model, X, y, scoring=scorer, cv=5)
print(f'CV Scores: {scores}')

解读用于技能评估的 D² pinball score

d2_pinball_score 作为一种技能分数,类似于均值回归中的 R² 系数。它衡量的是您的模型相对于基准模型(即始终预测训练数据 alpha 分位数的模型)所解释的偏差比例。1.0 表示完美模型,0.0 表示模型并不比基准模型更好,负值表示模型表现比基准模型差。

from sklearn.metrics import d2_pinball_score

skill_score = d2_pinball_score(y, y_pred, alpha=0.95)
print(f'D2 Pinball Score: {skill_score}')

正确可视化分位数预测

标准的回归可视化涉及检查点是否位于对角线上 (y_true = y_pred)。然而,对于分位数回归,点不会聚集在对角线上。相反,对于一个分位数 alpha,您会期望有特定比例的点落在对角线的上方和下方。例如,如果您预测的是 0.95 分位数,假设模型校准良好,则大约 95% 的实际值应该位于预测值之下。

处理多输出回归

如果您的目标变量是一个向量(多输出),mean_pinball_loss 和 d2_pinball_score 都提供了 multioutput 参数。默认情况下,该参数设置为 'uniform_average',它会计算每个输出的误差,然后取其平均值。您也可以使用 'raw_values' 来获取每个目标变量的误差数组,或者提供自定义的权重数组来优先考虑某些输出。

在训练和评估中对齐参数名称

scikit-learn 中参数命名的差异是常见的错误来源。估计器通常使用参数名称 'quantile' 来定义目标水平(例如,HistGradientBoostingRegressor(quantile=0.95))。然而,指标函数 mean_pinball_loss 和 d2_pinball_score 使用参数名称 'alpha'(例如,mean_pinball_loss(y_true, y_pred, alpha=0.95))。请务必确保这些值保持同步,以维持数学上的一致性。

检查清单

  • 验证估计器的分位数参数是否与指标的 alpha 参数匹配。
  • 确保在处理 pinball loss 时使用 make_scorer 并设置 greater_is_better=False。
  • 确认使用 d2_pinball_score 进行技能评估,而不是直接进行误差测量。
  • 检查多目标设置是否已针对多目标数据集正确配置。

Pinball loss 仅在分位数预测时具有严格的一致性;它不适用于预测均值或众数。预测误差图的视觉解释与针对条件均值的模型有所不同。

参考来源

  1. scikit-learn: model evaluation ↗
  2. scikit-learn: mean_absolute_error ↗
  3. scikit-learn: root_mean_squared_error ↗
返回顶部 ↑