哈喽,大家好~
咱们今天系统性地比较均方误差(MSE, Mean Squared Error)与平均绝对误差(MAE, Mean Absolute Error)的核心区别
MSE 的核心:平方惩罚大误差,追求“均值”的最优性。当你关心整体误差的能量(平方)并且你相信噪声近似高斯时,MSE 是统计上最优(MLE)且数值优化极其友好的选择。
MAE 的核心:线性惩罚大误差,追求“中位数”的稳健性。当数据存在重尾(heavy-tailed)或含异常值(outlier)时,MAE 对极端点的影响有上界,因而更稳健,但优化上因不可导点(在0处)相对更困难一些。
形式化定义、风险最小化与最优解
经验风险与目标:
给定数据集 ,回归模型 的两个常见经验风险如下:
MSE 经验风险:
MAE 经验风险:
期望风险与贝叶斯最优估计:
从统计学习角度,我们常考虑条件风险(以 条件化):
对于 MSE,对任意可测函数 ,其条件期望风险为
对 求导并令其为 0:
得到最优解
即 MSE 的贝叶斯最优预测是条件均值。
对于 MAE,
考虑次梯度(用 表示符号函数):
令其包含 0:
从而
即 MAE 的贝叶斯最优预测是条件中位数(在连续分布下唯一)。
结论:MSE 估计条件均值,MAE 估计条件中位数。若噪声对称且均值=中位数(如严格对称分布),两者一致;若噪声偏态或含异常值,它们会系统性偏离。
概率模型视角(MLE)
高斯噪声:若 ,负对数似然
最大似然等价于最小化 MSE。
拉普拉斯噪声:若 ,负对数似然
最大似然等价于最小化 MAE。
这给出“何时谁更优”的统计前提:高斯→MSE;拉普拉斯或重尾→MAE 更稳健。
优化性质与计算层面
凸性与可导性:
两者在参数为线性模型的情形下均为凸函数(在 上凸)。
MSE 光滑可导,梯度连续:
大型深度模型中它对优化算法(如 SGD/Adam)更友好。
MAE 在残差为 0 处不可导,但有次梯度:
优化可用亚梯度法或平滑近似(如 Huber 损失)。
问题条件与闭式解:
线性回归 + MSE ⇒ 正规方程有闭式解:
线性回归 + MAE ⇒ 无简单闭式解,经典方法可转为线性规划或用坐标下降/内点法,或用深度学习框架的 L1Loss 直接数值优化。
鲁棒性、影响函数与异常值
影响函数视角:
令残差 。从 M-estimation 角度定义“影响函数”近似与 相关。
MSE: ,(无界)。残差越大,影响线性增大,异常值权重爆炸。 MAE: ,(有界)。残差再大,影响也不再增长(就 y 方向而言),因此对 y 方向异常值更稳健。
注意:两者都可能受“高杠杆点”(极端的 x)影响,尤其在回归中,高杠杆点结合大残差会严重拉动拟合;MAE 在 y 异常上的影响有界,但对极端的 x 杠杆并非万无一失。
breakdown point(破坏点):
位置估计:样本均值的破坏点为 0(任意大异常值可将均值拖走),样本中位数破坏点为 0.5(半数以下异常不致于毁掉中位数)。
回归中的 LAD(MAE 回归)在理论上对 y 方向异常更稳健,但总体 breakdown point 仍不是 0.5;若存在强杠杆 x 异常仍可击穿。若需强鲁棒可用 LTS/LMS 或 RANSAC 等方法。
偏差-方差、效率与度量单位
MSE 惩罚平方残差,相当于给大残差更高权重,这通常降低估计的方差但增加对重尾的脆弱性。在高斯噪声下,MSE 对均值估计是有效(Cramér–Rao 下界达到)。
MAE 惩罚线性残差,稳健但在高斯情形下效率低于 MSE(需要更多样本达同样精度)。当噪声重尾或含异常,MAE 的稳健性会带来实际误差更低。
单位与可解释性:MSE 的单位是“平方单位”,RMSE 才回到原单位;MAE 直接是“原单位”,经常更易解释。
与 Huber 的联系
Huber 损失在小误差时像 MSE,大误差时像 MAE:
这是在优化友好与鲁棒性之间的折中。本文聚焦 MSE vs MAE,但实践中 Huber 常见。
一个完整案例
含异方差与异常值的线性回归
我们构造一个线性真模型,叠加随 x 变化的异方差高斯噪声,并注入一批强异常值。
分别使用 MSE 与 MAE 训练线性模型,比较拟合曲线、残差分布与训练动态。
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
import copy
import random
# 1) 随机种子
seed = 42
np.random.seed(seed)
torch.manual_seed(seed)
random.seed(seed)
# 2) 生成虚拟数据:线性真值 + 异方差 + 异常值
n = 2000
x = np.random.uniform(-3, 3, size=n)
x = np.sort(x) # 方便可视化
true_w, true_b = 1.2, -0.7
y_clean = true_w * x + true_b
# 异方差噪声: sigma 随 |x| 增大
sigma = 0.2 + 0.3 * np.abs(x)
y = y_clean + np.random.normal(0, sigma, size=n)
# 注入异常值(y方向):10%
outlier_ratio = 0.1
o = int(n * outlier_ratio)
outlier_idx = np.random.choice(n, size=o, replace=False)
y[outlier_idx] += np.random.normal(0, 6.0, size=o) + np.random.choice([-1, 1], size=o) * 8.0
is_outlier = np.zeros(n, dtype=bool)
is_outlier[outlier_idx] = True
# 转为 tensor
X = torch.tensor(x, dtype=torch.float32).view(-1, 1)
Y = torch.tensor(y, dtype=torch.float32).view(-1, 1)
# 3) 定义简单线性模型
class LinReg(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(1, 1, bias=True)
def forward(self, x):
return self.linear(x)
base_model = LinReg()
# 为公平性,MSE 与 MAE 从相同初始化出发
model_mse = copy.deepcopy(base_model)
model_mae = copy.deepcopy(base_model)
# 4) 训练设置
epochs = 800
lr = 0.05
criterion_mse = nn.MSELoss()
criterion_mae = nn.L1Loss()
opt_mse = optim.Adam(model_mse.parameters(), lr=lr)
opt_mae = optim.Adam(model_mae.parameters(), lr=lr)
loss_hist_mse = []
loss_hist_mae = []
# 5) 同步训练
for ep in range(epochs):
# MSE step
opt_mse.zero_grad()
pred_mse = model_mse(X)
loss_mse = criterion_mse(pred_mse, Y)
loss_mse.backward()
opt_mse.step()
loss_hist_mse.append(loss_mse.item())
# MAE step
opt_mae.zero_grad()
pred_mae = model_mae(X)
loss_mae = criterion_mae(pred_mae, Y)
loss_mae.backward()
opt_mae.step()
loss_hist_mae.append(loss_mae.item())
# 6) 训练后预测与残差
with torch.no_grad():
yhat_mse = model_mse(X).numpy().ravel()
yhat_mae = model_mae(X).numpy().ravel()
res_mse = y - yhat_mse
res_mae = y - yhat_mae
# 7) 计算评估指标
def rmse(a):
return np.sqrt(np.mean(a**2))
def mae(a):
return np.mean(np.abs(a))
rmse_mse_fit = rmse(res_mse)
mae_mse_fit = mae(res_mse)
rmse_mae_fit = rmse(res_mae)
mae_mae_fit = mae(res_mae)
# 8) 为绘图准备网格线
xx = np.linspace(x.min()-0.3, x.max()+0.3, 200)
with torch.no_grad():
XX = torch.tensor(xx, dtype=torch.float32).view(-1,1)
yy_mse_line = model_mse(XX).numpy().ravel()
yy_mae_line = model_mae(XX).numpy().ravel()
yy_true_line = true_w * xx + true_b
# 9) 可视化
plt.figure(figsize=(14, 10))
# 子图1:数据+拟合曲线(含异常值标记)
ax1 = plt.subplot(2,2,1)
ax1.scatter(x[~is_outlier], y[~is_outlier], s=22, c='cyan', edgecolor='k', alpha=0.75, label='Inliers')
ax1.scatter(x[is_outlier], y[is_outlier], s=28, c='magenta', edgecolor='k', alpha=0.9, label='Outliers')
ax1.plot(xx, yy_true_line, color='limegreen', lw=3, label='True line')
ax1.plot(xx, yy_mse_line, color='crimson', lw=2.5, label='MSE fit')
ax1.plot(xx, yy_mae_line, color='dodgerblue', lw=2.5, label='MAE fit')
ax1.set_title('拟合对比:含异方差与异常值', fontsize=12)
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.legend(loc='best')
ax1.grid(True, alpha=0.3)
# 子图2:残差分布对比(直方图+位置统计)
ax2 = plt.subplot(2,2,2)
bins = 32
ax2.hist(res_mse, bins=bins, color='crimson', alpha=0.55, density=True, label=f'MSE残差\nRMSE={rmse_mse_fit:.3f}\nMAE={mae_mse_fit:.3f}')
ax2.hist(res_mae, bins=bins, color='dodgerblue', alpha=0.55, density=True, label=f'MAE残差\nRMSE={rmse_mae_fit:.3f}\nMAE={mae_mae_fit:.3f}')
# 标注均值与中位数
mse_mean = np.mean(res_mse); mse_med = np.median(res_mse)
mae_mean = np.mean(res_mae); mae_med = np.median(res_mae)
ax2.axvline(mse_mean, color='crimson', ls='--', lw=2, label=f'MSE-mean={mse_mean:.2f}')
ax2.axvline(mae_med, color='dodgerblue', ls='-.', lw=2, label=f'MAE-median={mae_med:.2f}')
ax2.set_title('残差分布与位置统计', fontsize=12)
ax2.set_xlabel('residual')
ax2.set_ylabel('density')
ax2.legend(loc='best', fontsize=9)
ax2.grid(True, alpha=0.3)
# 子图3:训练曲线(log y 轴)
ax3 = plt.subplot(2,2,3)
epochs_arr = np.arange(1, epochs+1)
ax3.plot(epochs_arr, loss_hist_mse, color='crimson', lw=2.2, label='MSE loss')
ax3.plot(epochs_arr, loss_hist_mae, color='dodgerblue', lw=2.2, label='MAE loss')
ax3.set_yscale('log')
ax3.set_title('训练损失曲线(对数刻度)', fontsize=12)
ax3.set_xlabel('epoch')
ax3.set_ylabel('training loss (log)')
ax3.legend(loc='best')
ax3.grid(True, alpha=0.3)
# 子图4:损失与梯度对残差的形状(理论曲线)
ax4 = plt.subplot(2,2,4)
e = np.linspace(-10, 10, 400)
L_mse = e**2
L_mae = np.abs(e)
g_mse = 2*e
g_mae = np.sign(e)
# 左轴:损失
ln1, = ax4.plot(e, L_mse, color='crimson', lw=2, label='MSE loss e^2')
ln2, = ax4.plot(e, L_mae, color='dodgerblue', lw=2, label='MAE loss |e|')
ax4.set_xlabel('residual e')
ax4.set_ylabel('loss')
ax4.set_title('损失与梯度随残差的变化', fontsize=12)
ax4.grid(True, alpha=0.3)
# 右轴:梯度
ax4b = ax4.twinx()
ln3, = ax4b.plot(e, g_mse, color='orange', lw=2, ls='--', label='d/d e MSE = 2e')
ln4, = ax4b.plot(e, g_mae, color='limegreen', lw=2, ls='-.', label='d/d e MAE = sign(e)')
ax4b.set_ylabel('gradient w.r.t e')
# 合并图例
lines = [ln1, ln2, ln3, ln4]
labels = [l.get_label() for l in lines]
ax4.legend(lines, labels, loc='upper left', fontsize=9)
plt.tight_layout()
plt.show()
# 10) 打印回归系数
w_mse = list(model_mse.parameters())[0].detach().numpy().ravel()[0]
b_mse = list(model_mse.parameters())[1].detach().numpy().ravel()[0]
w_mae = list(model_mae.parameters())[0].detach().numpy().ravel()[0]
b_mae = list(model_mae.parameters())[1].detach().numpy().ravel()[0]
print(f"True w={true_w:.3f}, b={true_b:.3f}")
print(f"MSE fit: w={w_mse:.3f}, b={b_mse:.3f}, RMSE={rmse_mse_fit:.3f}, MAE={mae_mse_fit:.3f}")
print(f"MAE fit: w={w_mae:.3f}, b={b_mae:.3f}, RMSE={rmse_mae_fit:.3f}, MAE={mae_mae_fit:.3f}")

图一,拟合对比:展示在异方差与存在 10% 明显异常值(y 方向)的情况下,两种损失学得的回归直线。
MSE 曲线更受异常值牵引(尤其是偏离极大的点),出现明显偏斜,使整体拟合偏离多数样本的“中位趋势”;
MAE 曲线对极端点的影响有上限,拟合更贴近主干数据云的中位走向,更稳健。
这印证了“平方惩罚更偏重大残差”的直觉。
图二,残差分布:叠加两种残差的直方图(密度化),并标注位置统计(例如 MSE 残差均值、MAE 残差中位数)。说明:
MSE 优化使“平方意义下的平均偏差”最小,残差均值更趋近 0;但在重尾/异常值下,方差更大(长尾更明显)。
MAE 优化使“绝对偏差的中位位置”居中,残差中位数更接近 0;分布对异常值相对不那么敏感。
图三,训练曲线:对数刻度下显示两种损失的训练过程。
MSE 的梯度平滑、收敛稳定,下降较为迅速;
MAE 因不可导点(在 e=0)存在,用次梯度下降会出现台阶感、收敛相对缓一些,但能到稳健解。
若在没有异常值的理想高斯环境中,MSE 往往更快更优(统计效率高);但有异常时,MAE 的最终质量更可能更好(具体看你评价指标)。
图四,损失与梯度形状:理论曲线清晰展示了
MSE 损失 随残差幅度快速增长,其梯度 无界;大残差样本在训练中被赋予极高“话语权”,是异常值敏感的根源;
MAE 损失 线性增长,其梯度 有界;残差再大也不会成倍放大训练驱动力,解释了其鲁棒性。
核心区别:
统计目标:MSE 学的是条件均值,MAE 学的是条件中位数; 分布假设:高斯噪声 → MSE 为 MLE;拉普拉斯或重尾 → MAE 更稳健; 鲁棒性:MSE 对大残差影响无界,异常值会极大牵引;MAE 在 y 方向有界影响,更稳健,但仍可能受高杠杆 x 的影响; 优化:MSE 光滑易优化有闭式解(线性情形);MAE 不可导但可用次梯度、线性规划或 Huber 平滑; 可解释性:MAE 单位与原量纲一致;MSE 需取平方根(RMSE)才具直观单位。
侧重点与选择建议:
如果数据干净、噪声近似高斯、且你关心整体平方误差:优先 MSE(或 RMSE 作为指标)。 如果数据含异常或重尾、你关心典型个体的偏差或中位趋势:考虑 MAE 或 Huber。 如果你需要分布的不同分位数(如 90% 分位的保障水平):用分位数回归(pinball loss)。 若你处在工业系统中,先做数据清洗/异常检测,再用 MSE 通常也能得到优雅解;清洗不充分时,MAE/Huber 能提供更稳健的第一道防线。
本文案例中,在含异方差与 10% 异常值的设置下,MAE 拟合更贴近主干数据,中位残差居中更明显;MSE 则更受异常点牵引,残差长尾更显著。
损失与梯度曲线清楚说明了“权重放大”的机制差别:平方损失“惩大放小”、绝对损失“等权对待”。
最后

