在应对含有离群值的数据时,Huber回归以其独特的损失函数设计,在模型稳健性与预测精度之间实现了理想的平衡。在之前的文章损失函数总结中,我们有简单的介绍Huber Loss,本文我们就来深入学习一下Huber回归的原理、优势。
1 引入
在机器学习的任务中,离群值往往是导致模型性能下降的重要因素。以线性回归为例,标准的线性回归通常依赖最小二乘损失函数,在数据整体服从正态分布的理想情况下,它可以很好地拟合样本。然而在实际应用中,数据往往包含极端值,这些离群点可能对损失函数产生过大的影响。
这张图片展示了三种损失函数在面对离群点时的表现差异。上半部分的两个图说明了线性回归在存在离群值时,会向离群点弯曲,从而影响整体拟合效果。下半部分则用公式对比了三种损失函数:
- 左边是平方损失函数( L = [ y − f ( x ) ] 2 L = [y - f(x)]^2 L=[y−f(x)]2),对离群点非常敏感,中心偏向均值(mean);
- 右边是绝对值损失函数( L = ∣ y − f ( x ) ∣ L = |y - f(x)| L=∣y−f(x)∣),对离群点更鲁棒,中心偏向中位数(median);
- 中间的红色部分表示Huber 损失函数,它是一种介于两者之间的平衡方案,结合了两者的优点,在保留对小误差敏感度的同时,也对离群点具有一定的鲁棒性。
问题出在哪?
假设你有一个包含两个特征( X 1 X_1 X1和 X 2 X_2 X2)的数据集,你正在对其进行线性回归。然而,一些噪声或离群值被引入到了数据中。
假设 y y y 值的离群点异常低,与其应有的数值相比低很多。你获得的数据看起来像这样:
在这里插入图片描述
但如果你仔细考虑 X − Y X-Y X−Y 数据的斜率,那些 X X X 值对应的期望 y y y 值应该更高,像这样:
我们可以通过简单的探索性数据分析(EDA)来识别并剔除这些离群点,然后再构建回归模型。但你不可能捕捉到所有离群点,特别是在大规模和高维度情况下。
因此,我们需要一个对离群值鲁棒的回归算法,Huber回归就是解决这个问题的。
2 Huber回归
2.1 原理
在统计学中,Huber损失是一种特定的损失函数,广泛用于离群值可能影响回归精度的情况。损失函数定义如下:
L δ ( y , f ( x ) ) = { 1 2 ( y − f ( x ) ) 2 for ∣ y − f ( x ) ∣ ≤ δ δ ( ∣ y − f ( x ) ∣ − 1 2 δ ) otherwise L_\delta(y, f(x)) = \begin{cases} \frac{1}{2}(y - f(x))^2 & \text{for } |y - f(x)| \leq \delta \\ \delta(|y - f(x)| - \frac{1}{2}\delta) & \text{otherwise} \end{cases} Lδ(y,f(x))={21(y−f(x))2δ(∣y−f(x)∣−21δ)for ∣y−f(x)∣≤δotherwise
我们可以看到,当残差 ∣ y − f ( x ) ∣ |y - f(x)| ∣y−f(x)∣ 小于某个阈值 δ \delta δ时,使用的是平方损失;当残差超过该阈值时,使用的是绝对值损失的线性函数。这个函数的选择和参数 δ \delta δ的调节至关重要,因为它控制了何时从平方误差切换为线性误差。
平方误差倾向于让预测结果靠近所有值的平均位置,绝对误差更关注数据的中间位置,因此更不容易被少数离群点影响。而Huber损失是一种在这两者之间的折中方案:它在面对离群值时具备鲁棒性,但又不会完全忽略它们。该损失函数通过参数 δ \delta δ 实现可调节性。
2.2 代码示例
以下代码创建了一个合成数据集,并人为添加了离群点:
import numpy as np
from sklearn.datasets import make_regression
rng = np.random.RandomState(0)
X, y, coef = make_regression(
n_samples=200, n_features=2, noise=4.0, coef=True, random_state=0
)
# 前四个点是离群点
X[:4] = rng.uniform(10, 20, (4, 2))
y[:4] = rng.uniform(10, 20, 4)
然后使用Scikit-learn内置的HuberRegressor
和LinearRegression
进行拟合:
from sklearn.linear_model import HuberRegressor, LinearRegression
huber = HuberRegressor().fit(X, y)
linear = LinearRegression().fit(X, y)
接下来我们预测第一个数据点的 y y y 值:
linear.predict(X[:1,])
>> array([87.38004436])
如预期,线性回归预测值很低,因为基于最小二乘损失(least-squared loss
)的拟合向离群值弯曲了。然而,Huber估计器预测了一个更合理(较高)的值:
huber.predict(X[:1,])
>> array([806.72000092])
我们现在使用Huber估计出的系数绘制最佳拟合线:
huber_y1 = np.arange(-2.5,20,0.01)*huber.coef_[0] + \
np.arange(-2.5,20,0.01)*huber.coef_[1] + \
huber.intercept_
plt.figure(dpi=120)
plt.scatter(X[:,0],y)
plt.plot(np.arange(-2.5,20,0.01), huber_y1, color='red', linestyle='--')
plt.show()
如下图所示:
3 总结
需要注意的是,Huber的表现依赖于 δ \delta δ的选择:设得过大,相当于回归退化为普通最小二乘;设得过小,又会变得过于保守。此外,当离群点占据数据集的大部分时,Huber方法也可能丧失对整体趋势的捕捉能力。
Theil-Sen
估计器是另一种强鲁棒性的线性回归方法,它基于中位数统计而非均值,更能抵抗极端值的干扰,适合用于包含大量变量的高维数据建模任务。这个在Scikit-learn里有提供实现。
Huber回归为我们提供了在噪声数据和离群值频发环境中构建可靠模型的可能。通过合理选择方法与参数,我们可以避免模型因少量异常数据而失真,实现更贴近现实趋势的预测。
虽然Huber损失最初用于线性回归问题,但它的鲁棒性优势使其广泛应用于其他任务中。例如,在自然语言处理领域,Huber损失可以结合BERT等模型用于预测情感强度值,提升对标注误差或极端样本的容错能力。此外,它也被用于时间序列预测、异常检测等需要回归目标的任务中,是一种通用性强、稳定性好的损失函数选择。