1. 为什么需要预处理?
真实数据往往存在以下问题:
| 问题 | 示例 |
|---|---|
| 量纲不同 | 收入:2-10万美元,房间数:3-8个,房龄:1-50年 |
| 数值范围差异大 | 面积:50-200,房价:50-200万,相差1000倍 |
| 分布不均匀 | 有些特征集中在某个区间 |
| 异常值 | 个别数据偏离正常范围 |
2. 标准化公式
Z-score 标准化(零均值标准化):
xscaled=x−μσx_{scaled} = \frac{x - \mu}{\sigma}xscaled=σx−μ
其中:
- μ\muμ 是特征的均值
- σ\sigmaσ 是特征的标准差
标准化后,特征通常在 [-3, 3] 范围内(约 99.7% 的数据)。
为什么是 [-3, 3]?
这是基于正态分布的"68-95-99.7"规则(经验法则)。
标准化将数据转换为:
- 均值 μ=0\mu = 0μ=0
- 标准差 σ=1\sigma = 1σ=1
如果原始数据近似正态分布,标准化后服从标准正态分布 N(0,1)N(0, 1)N(0,1):
▲ 概率密度
│
┌────┴────┐
╱ │ │ ╲
╱ │ │ ╲
╱ │ │ ╲
╱ │ │ ╲
────┼───┼───┼───┼───┼───┼───▶ x
-3σ -2σ -1σ 0 1σ 2σ 3σ
│ │ │ │ │ │ │
└───┴───┴───┴───┴───┴───┘
│←─68.2%─→│
│←────95.4%────→│
│←──────99.7%──────→│
| 范围 | 包含数据比例 | 说明 |
|---|---|---|
| [−1,1][-1, 1][−1,1](±1σ) | 68.2% | 约 2/3 的数据 |
| [−2,2][-2, 2][−2,2](±2σ) | 95.4% | 绝大部分数据 |
| [−3,3][-3, 3][−3,3](±3σ) | 99.7% | 几乎所有数据 |
结论:标准化后,超出 [-3, 3] 范围的数据只占 0.3%,通常是异常值。
非正态分布的情况
即使原始数据不完全服从正态分布,根据切比雪夫不等式:
P(∣X−μ∣≥kσ)≤1k2P(|X - \mu| \geq k\sigma) \leq \frac{1}{k^2}P(∣X−μ∣≥kσ)≤k21
对于 k=3k=3k=3:
P(∣X∣≥3)≤19≈11.1%P(|X| \geq 3) \leq \frac{1}{9} \approx 11.1\%P(∣X∣≥3)≤91≈11.1%
即至少 88.9% 的数据在 [-3, 3] 范围内。
所以无论分布形态如何,[-3, 3] 都是一个合理的参考范围。
3. 标准化的作用
| 作用 | 说明 |
|---|---|
| 消除量纲差异 | 所有特征都变成无量纲的数值 |
| 统一数值范围 | 各特征通常在 [-3, 3] 范围内 |
| 加速梯度下降收敛 | 损失函数等高线变圆,梯度直指最小值 |
| 公平比较特征重要性 | 参数大小直接反映特征影响力 |
4. 对收敛速度的影响
什么是等高线?
等高线 是损失函数 J(θ)J(\theta)J(θ) 在参数空间中的可视化表示。
对于两个参数 θ1\theta_1θ1 和 θ2\theta_2θ2,损失函数可以表示为三维曲面。等高线是将这个曲面"切片"后投影到二维平面:
损失 J(θ)
▲
│ ● 最小值点
│ ╱│╲
│ ╱ │ ╲
│ ╱ │ ╲ ──── 不同高度切面
│ ╱ │ ╲
│ ╱ │ ╲
│╱─────┼─────╲
└───────────────▶ θ₁
↘
θ₂
每一条等高线代表损失值相同的所有参数组合,即:
J(θ1,θ2)=C(C为常数)J(\theta_1, \theta_2) = C \quad (C 为常数)J(θ1,θ2)=C(C为常数)
为什么等高线是椭圆或圆形?
损失函数(均方误差)的形式:
J(θ)=12m∑i=1m(θ1x1(i)+θ2x2(i)−y(i))2J(\theta) = \frac{1}{2m} \sum_{i=1}^{m} (\theta_1 x_1^{(i)} + \theta_2 x_2^{(i)} - y^{(i)})^2J(θ)=2m1i=1∑m(θ1x1(i)+θ2x2(i)−y(i))2
展开后可写成二次型:
J(θ)≈aθ12+bθ22+cθ1θ2+dJ(\theta) \approx a\theta_1^2 + b\theta_2^2 + c\theta_1\theta_2 + dJ(θ)≈aθ12+bθ22+cθ1θ2+d
等高线的形状取决于二次项系数的比例:
| 条件 | 等高线形状 | 原因 |
|---|---|---|
| a≈ba \approx ba≈b | 圆形 | 两个参数的"曲率"相近 |
| a≠ba \neq ba=b(差异大) | 椭圆 | 一个方向变化快,另一个慢 |
数学推导:为什么特征范围不同会导致椭圆
假设简化情况:单特征线性回归
J(θ)=12m∑i=1m(x(i)θ−y(i))2J(\theta) = \frac{1}{2m} \sum_{i=1}^{m} (x^{(i)}\theta - y^{(i)})^2J(θ)=2m1i=1∑m(x(i)θ−y(i))2
对 θ\thetaθ 求二阶导数(曲率):
∂2J∂θ2=1m∑i=1mx(i)2\frac{\partial^2 J}{\partial \theta^2} = \frac{1}{m} \sum_{i=1}^{m} x^{(i)2}∂θ2∂2J=m1i=1∑mx(i)2
曲率 = 特征值的平方均值
这意味着:
- 特征范围大 → xxx 值大 → 曲率大 → 等高线在这个方向"陡峭"
- 特征范围小 → xxx 值小 → 曲率小 → 等高线在这个方向"平坦"
扩展到两个特征:
∂2J∂θ12=1m∑x12,∂2J∂θ22=1m∑x22\frac{\partial^2 J}{\partial \theta_1^2} = \frac{1}{m} \sum x_1^2, \quad \frac{\partial^2 J}{\partial \theta_2^2} = \frac{1}{m} \sum x_2^2∂θ12∂2J=m1∑x12,∂θ22∂2J=m1∑x22
当 x1x_1x1 和 x2x_2x2 范围差异大时,曲率差异大,等高线呈椭圆。
标准化后,x1x_1x1 和 x2x_2x2 范围相近,曲率相近,等高线接近圆形。
梯度与等高线的关系
梯度方向垂直于等高线,指向损失增大的方向。
梯度下降沿负梯度方向前进(损失减小)。
圆形等高线 椭圆形等高线
╭─────╮ ╭───────╮
╱ ↑ ╲ ╱ ↑ ╲
│ ●─────│ 梯度 │ ●──────│ 梯度
╲ ╱ 直指 ╲ ╱ 偏离
╰─────╯ 中心 ╰───────╯ 中心
快速收敛 需要震荡多次
不做标准化
假设特征范围:
- x1x_1x1(收入):2-10(范围小)
- x2x_2x2(房龄):1-50(范围大)
损失函数等高线呈椭圆形:
┌─────────────────────┐
│ ╭───────╮ │ 椭圆等高线
│ ╭─────────╮ │ 梯度方向偏离最优
│ ╭───────────╮ │ 需要很多次震荡才能收敛
│ ╭─────────────╮ │
│╭───────────────╮ │
└─────────────────────┘
梯度下降会沿着椭圆边缘"震荡"前进,收敛慢,甚至可能发散。
原因:
- 大范围特征的参数更新步长小
- 小范围特征的参数更新步长大
- 两者不协调,导致震荡
标准化后
所有特征范围相近,等高线接近圆形:
┌─────────────────────┐
│ ╭─────╮ │ 圆形等高线
│ ╭─────╮ │ 梯度直指中心
│ ╭─────╮ │ 快速收敛
│ ╭─────╮ │
│ ╭─────╮ │
└─────────────────────┘
梯度下降能直接朝最优解方向前进。
5. 对预测结果的影响
| 方面 | 不标准化 | 标准化后 |
|---|---|---|
| 收敛速度 | 慢,可能需要数千次迭代 | 快,几百次即可收敛 |
| 学习率选择 | 需要非常小的 α,否则发散 | 可以用较大的 α(如 0.1) |
| 参数解释 | 参数大小受特征范围影响,难以比较 | 参数直接反映特征重要性 |
| 预测结果 | 最终结果相同(理论上) | 相同,但更稳定 |
关键结论 :标准化不改变最终预测结果(数学上等价),但能将收敛速度提高 10-100 倍。
6. 数学证明:预测结果等价
原始模型
y=θ0+θ1x1+θ2x2y = \theta_0 + \theta_1 x_1 + \theta_2 x_2y=θ0+θ1x1+θ2x2
标准化后的模型
y=θ0′+θ1′⋅x1−μ1σ1+θ2′⋅x2−μ2σ2y = \theta_0' + \theta_1' \cdot \frac{x_1 - \mu_1}{\sigma_1} + \theta_2' \cdot \frac{x_2 - \mu_2}{\sigma_2}y=θ0′+θ1′⋅σ1x1−μ1+θ2′⋅σ2x2−μ2
参数转换关系
将标准化模型展开:
y=θ0′+θ1′σ1x1−θ1′μ1σ1+θ2′σ2x2−θ2′μ2σ2y = \theta_0' + \frac{\theta_1'}{\sigma_1} x_1 - \frac{\theta_1' \mu_1}{\sigma_1} + \frac{\theta_2'}{\sigma_2} x_2 - \frac{\theta_2' \mu_2}{\sigma_2}y=θ0′+σ1θ1′x1−σ1θ1′μ1+σ2θ2′x2−σ2θ2′μ2
与原始模型对应:
θ1=θ1′σ1,θ2=θ2′σ2\theta_1 = \frac{\theta_1'}{\sigma_1}, \quad \theta_2 = \frac{\theta_2'}{\sigma_2}θ1=σ1θ1′,θ2=σ2θ2′
θ0=θ0′−θ1′μ1σ1−θ2′μ2σ2\theta_0 = \theta_0' - \frac{\theta_1' \mu_1}{\sigma_1} - \frac{\theta_2' \mu_2}{\sigma_2}θ0=θ0′−σ1θ1′μ1−σ2θ2′μ2
预测时的一致性
预测新数据时,同样对输入做标准化:
y^=θ0′+θ1′⋅xnew−μσ\hat{y} = \theta_0' + \theta_1' \cdot \frac{x_{new} - \mu}{\sigma}y^=θ0′+θ1′⋅σxnew−μ
结果与原始模型预测一致(数学等价)。
7. Python 实现
标准化函数
python
import numpy as np
def standardize(X):
"""
特征标准化(Z-score)
参数:
X: 特征矩阵 (m, n)
返回:
X_scaled: 标准化后的特征矩阵
mu: 均值向量(保存用于新数据)
sigma: 标准差向量(保存用于新数据)
"""
mu = np.mean(X, axis=0)
sigma = np.std(X, axis=0)
X_scaled = (X - mu) / sigma
return X_scaled, mu, sigma
预处理完整流程
python
def preprocess_data(X):
"""
完整预处理:标准化 + 添加偏置列
参数:
X: 原始特征矩阵 (m, n)
返回:
X_final: 处理后的特征矩阵 (m, n+1),含偏置列
mu: 均值向量
sigma: 标准差向量
"""
# 标准化
X_scaled, mu, sigma = standardize(X)
# 添加偏置列 (x0 = 1)
m = X.shape[0]
X_final = np.column_stack([np.ones(m), X_scaled])
return X_final, mu, sigma
预测时使用相同参数
python
def predict(x_new, theta, mu, sigma):
"""
使用训练好的模型预测新数据
参数:
x_new: 新数据特征向量 (n,)
theta: 训练得到的参数向量
mu: 训练时的均值向量
sigma: 训练时的标准差向量
返回:
预测值
"""
# 使用训练数据的 mu 和 sigma 进行标准化
x_scaled = (x_new - mu) / sigma
# 添加偏置项
x_final = np.array([1, *x_scaled])
# 预测
return np.dot(x_final, theta)
完整示例
python
# 训练阶段
X_raw = np.array([[2, 10], [4, 20], [6, 30], [8, 40]])
y = np.array([10, 20, 30, 40])
# 预处理
X, mu, sigma = preprocess_data(X_raw)
print(f"均值: {mu}")
print(f"标准差: {sigma}")
# 训练(梯度下降)
theta = gradient_descent(X, y)
# 预测阶段
x_new = np.array([5, 25]) # 新数据
prediction = predict(x_new, theta, mu, sigma)
print(f"预测结果: {prediction}")
8. 其他预处理方法
Min-Max 归一化
将特征缩放到 [0, 1] 范围:
xnormalized=x−xminxmax−xminx_{normalized} = \frac{x - x_{min}}{x_{max} - x_{min}}xnormalized=xmax−xminx−xmin
python
def min_max_normalize(X):
x_min = np.min(X, axis=0)
x_max = np.max(X, axis=0)
return (X - x_min) / (x_max - x_min), x_min, x_max
适用场景:图像处理、神经网络输入。
对数变换
对大范围特征取对数,压缩数值范围:
xlog=log(x+1)x_{log} = \log(x + 1)xlog=log(x+1)
适用场景:收入、房价等呈指数分布的特征。
Robust 标准化
使用中位数和四分位距,对异常值更鲁棒:
xrobust=x−medianIQRx_{robust} = \frac{x - median}{IQR}xrobust=IQRx−median
其中 IQR=Q3−Q1IQR = Q_3 - Q_1IQR=Q3−Q1(四分位距)。
python
from sklearn.preprocessing import RobustScaler
scaler = RobustScaler()
X_scaled = scaler.fit_transform(X)
9. 不同方法对比
| 方法 | 公式 | 输出范围 | 适用场景 |
|---|---|---|---|
| Z-score | x−μσ\frac{x - \mu}{\sigma}σx−μ | 约 [-3, 3] | 梯度下降、线性模型 |
| Min-Max | x−minmax−min\frac{x - min}{max - min}max−minx−min | [0, 1] | 神经网络、图像 |
| Robust | x−medianIQR\frac{x - median}{IQR}IQRx−median | 不固定 | 有异常值的数据 |
| Log | log(x+1)\log(x + 1)log(x+1) | 不固定 | 指数分布特征 |
10. 注意事项
-
保存均值和标准差 :训练时的 μ\muμ 和 σ\sigmaσ 必须保存,预测新数据时使用相同参数
-
不要对目标值标准化:通常只对特征 X 标准化,目标值 y 保持原样
-
测试数据用训练参数 :测试集用训练集的 μ\muμ 和 σ\sigmaσ,不要重新计算
-
偏置列不标准化 :x0=1x_0 = 1x0=1 是偏置项,不参与标准化
python
# 错误:对整个矩阵标准化(包括偏置列)
X_with_bias = np.column_stack([np.ones(m), X])
X_scaled = (X_with_bias - mu_all) / sigma_all # 错误!
# 正确:只对特征标准化,再添加偏置列
X_scaled = (X - mu) / sigma
X_final = np.column_stack([np.ones(m), X_scaled]) # 正确