归一化与标准化——公式与对比

1. 前言

在机器学习和数据分析中,原始数据的各特征往往具有不同的量纲和取值范围。例如,一个特征取值在 01 之间,另一个特征可能取值在 100010000 之间。如果直接输入模型,取值范围大的特征会主导梯度更新,导致模型收敛缓慢甚至不收敛。

特征缩放(Feature Scaling)是解决这一问题的关键步骤,其中最常用的两种方法是归一化标准化。本文将详细讲解两者的定义、公式、实现以及适用场景。

2. 核心概念

术语 英文 目标区间 受异常值影响
归一化 Normalization (Min-Max Scaling) 任意 $[a, b]$(默认 $[0, 1]$) (严重)
标准化 Standardization (Z-Score Scaling) 均值 0,标准差 1 (相对鲁棒)

两种方法都不改变数据分布的形状,仅改变数据的尺度和位置。

3. 归一化(Min-Max Normalization)

3.1 定义

归一化通过线性变换将数据从原始范围 $[x_{\min},\ x_{\max}]$ 映射到任意指定的目标区间 $[a, b]$。其本质是两步操作:先消除量纲(除以全距),再平移到目标位置。

最常用的目标区间是 $[0, 1]$,但根据实际需求可以灵活选择 $[-1, 1]$、$[0, 255]$ 等任意范围。

3.2 通用公式(映射到任意 $[a, b]$)

设原始数据为 $x$,$x_{\min}$ 和 $x_{\max}$ 分别为该特征的最小值和最大值,目标区间为 $[a, b]$(其中 $a < b$)。整个过程分为两步:

第一步:将数据压缩到 $[0, 1]$ 区间:

$$
x’ = \frac{x - x_{\min}}{x_{\max} - x_{\min}}
$$

第二步:将 $x’$ 拉伸并平移到目标区间 $[a, b]$:

$$
x’’ = a + x’ \cdot (b - a)
$$

合并两步即得一步公式:

$$
x’’ = a + \frac{(x - x_{\min})(b - a)}{x_{\max} - x_{\min}}
$$

反归一化(恢复到原始尺度):

$$
x = x_{\min} + \frac{(x’’ - a)(x_{\max} - x_{\min})}{b - a}
$$

3.3 特例:映射到 $[0, 1]$

当 $a = 0,\ b = 1$ 时,第二步 $x’’ = 0 + x’ \cdot 1 = x’$,通用公式退化为最常见的 Min-Max 归一化,此时 $x’$ 即为最终结果:

$$
x’ = \frac{x - x_{\min}}{x_{\max} - x_{\min}}
$$

3.4 计算示例

设某特征的一组值为 $[10, 20, 30, 40, 50]$,$x_{\min} = 10$,$x_{\max} = 50$。

例 1:映射到 $[0, 1]$,对 $x = 30$:

第一步:$x’ = \displaystyle\frac{30 - 10}{50 - 10} = 0.5$

由于 $a = 0,\ b = 1$,$x’’ = x’ = 0.5$。

结果:$[0,\ 0.25,\ 0.5,\ 0.75,\ 1]$

例 2:映射到 $[-1, 1]$($a = -1,\ b = 1$),对 $x = 30$:

第一步:$x’ = \displaystyle\frac{30 - 10}{50 - 10} = 0.5$

第二步:$x’’ = -1 + 0.5 \times (1 - (-1)) = -1 + 0.5 \times 2 = 0$

结果:$[-1,\ -0.5,\ 0,\ 0.5,\ 1]$

例 3:映射到 $[0, 255]$($a = 0,\ b = 255$,如图像像素值),对 $x = 30$:

第一步:$x’ = \displaystyle\frac{30 - 10}{50 - 10} = 0.5$

第二步:$x’’ = 0 + 0.5 \times 255 = 127.5$

结果:$[0,\ 63.75,\ 127.5,\ 191.25,\ 255]$

3.5 sklearn 实现与 fit 验证

MinMaxScalerfit 方法会从数据中学习 data_min_(每个特征的最小值)和 data_max_(每个特征的最大值),并据此计算出 scale_(缩放因子)和 min_(偏移量)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import numpy as np
from sklearn.preprocessing import MinMaxScaler

data = np.array([10, 20, 30, 40, 50], dtype=float).reshape(-1, 1)

scaler = MinMaxScaler(feature_range=(0, 1)) # 默认 feature_range=(0, 1)

# fit:从训练数据中学习参数
scaler.fit(data)

# 查看 fit 学到的参数
print("data_min_:", scaler.data_min_) # [10.] — 每个特征的最小值
print("data_max_:", scaler.data_max_) # [50.] — 每个特征的最大值
print("scale_: ", scaler.scale_) # [0.025] — 缩放因子 = (b - a) / (data_max - data_min)
print("min_: ", scaler.min_) # [-0.25] — 归一化偏移量

# transform:使用学到的参数转换数据
result = scaler.transform(data)
print("结果:", result.flatten())
# 输出: [0. 0.25 0.5 0.75 1. ]

# 验证手动计算:scale_ = (1 - 0) / (50 - 10) = 0.025 ✓
# 验证手动计算:min_ = 0 - 10 * 0.025 = -0.25 ✓

# 也可以一步到位
print(scaler.fit_transform(data).flatten()) # 同上

指定其他目标区间时,feature_range 参数直接控制 scale_min_ 的计算:

1
2
3
4
5
6
7
8
9
scaler = MinMaxScaler(feature_range=(-1, 1))
scaler.fit(data)

print("data_min_:", scaler.data_min_) # [10.]
print("data_max_:", scaler.data_max_) # [50.]
print("scale_: ", scaler.scale_) # [0.05] — (1 - (-1)) / (50 - 10) = 2/40
print("min_: ", scaler.min_) # [-1.5] — -1 - 10 * 0.05
print("结果:", scaler.transform(data).flatten())
# 输出: [-1. -0.5 0. 0.5 1. ]

3.6 适用场景

  • 需要数据严格落在 $[0, 1]$ 区间的场景(如图像像素值归一化);
  • 使用梯度下降且对输入尺度敏感的模型(如神经网络、SVM);
  • 距离度量为核心的算法(如 KNN、K-Means)。

4. 标准化(Z-Score Standardization)

4.1 定义

标准化将数据转换为均值为 0、标准差为 1 的分布,使其符合标准正态分布的特性。

4.2 公式

设原始数据为 $x$,$\mu$ 为该特征的均值,$\sigma$ 为该特征的标准差:

$$
x’ = \frac{x - \mu}{\sigma}
$$

其中:

  • $x$ 为原始值;
  • $x’$ 为标准化后的值(也称为 Z-Score);
  • $\mu$ 为样本均值:$\mu = \frac{1}{n}\sum_{i=1}^{n}x_i$;
  • $\sigma$ 为样本标准差:$\sigma = \sqrt{\frac{1}{n}\sum_{i=1}^{n}(x_i - \mu)^2}$。

注意:在统计学中,样本标准差常用 $n-1$ 作为分母(贝塞尔校正);在机器学习中,$n$ 和 $n-1$ 的影响通常可忽略不计。sklearnStandardScaler 默认使用 $n-1$ 即 ddof=1

反标准化(恢复到原始尺度):

$$
x = x’ \cdot \sigma + \mu
$$

4.3 标准化后的统计特性

对标准化后的数据 $x’$:

  • 均值:$\mu’ = 0$
  • 标准差:$\sigma’ = 1$

标准化不会改变数据分布的偏度和峰度,只进行平移和缩放。

4.4 计算示例

设某特征的一组值为 $[10, 20, 30, 40, 50]$:

  • 均值:$\mu = \frac{10+20+30+40+50}{5} = 30$
  • 标准差:$\sigma = \sqrt{\frac{(10-30)^2 + (20-30)^2 + (30-30)^2 + (40-30)^2 + (50-30)^2}{5}} = \sqrt{\frac{1000}{5}} = \sqrt{200} \approx 14.142$
  • 对 $x = 30$ 标准化:

$$
x’ = \frac{30 - 30}{14.142} = 0
$$

标准化结果为 $[-1.414, -0.707, 0, 0.707, 1.414]$。

4.5 sklearn 实现与 fit 验证

StandardScalerfit 方法会从数据中学习 mean_(每个特征的均值)和 scale_(每个特征的标准差,默认使用 ddof=1 即 $n-1$ 作为分母)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import numpy as np
from sklearn.preprocessing import StandardScaler

data = np.array([10, 20, 30, 40, 50], dtype=float).reshape(-1, 1)

scaler = StandardScaler()

# fit:从训练数据中学习参数
scaler.fit(data)

# 查看 fit 学到的参数
print("mean_: ", scaler.mean_) # [30.] — 每个特征的均值
print("scale_:", scaler.scale_) # [15.8114] — 每个特征的标准差(ddof=1)
# 手动验证:均值 = (10+20+30+40+50)/5 = 30 ✓
# 手动验证:std(ddof=1) = sqrt(((10-30)²+(20-30)²+...)/4) = sqrt(1000/4) ≈ 15.811 ✓

# transform:使用学到的参数转换数据
result = scaler.transform(data)
print("结果:", result.flatten())
# 输出: [-1.2649 -0.6325 0. 0.6325 1.2649]

# 验证转换结果
print("转换后均值:", result.mean()) # ≈ 0(接近零,存在数值误差)
print("转换后标准差:", result.std()) # ddof=0 时 ≈ 1

注意:sklearn 的 StandardScaler 默认使用 ddof=1(即分母为 $n-1$ 的样本标准差)。若需使用总体标准差(除以 $n$),可自行计算验证,但对实际应用影响极小。

4.6 适用场景

  • 数据近似正态分布时效果最佳;
  • PCA、LDA 等依赖协方差矩阵的降维算法(要求零均值);
  • 线性回归、逻辑回归、岭回归等正则化方法;
  • 对异常值有一定容忍度的场景。

5. 归一化与标准化的对比

5.1 关键差异

维度 归一化 标准化
公式 $\displaystyle x’ = \frac{x - x_{\min}}{x_{\max} - x_{\min}},\quad x’’ = a + x’ \cdot (b - a)$ $\displaystyle x’ = \frac{x - \mu}{\sigma}$
输出范围 严格限定在 $[a, b]$(默认为 $[0, 1]$) 无界,约 99.7% 落在 $[-3, 3]$(若正态)
对异常值 极敏感——异常值会压缩正常数据的分布范围 较鲁棒——异常值影响均值和标准差的程度相对有限
依赖参数 $x_{\min}$、$x_{\max}$ $\mu$、$\sigma$
分布假设 无(但正态分布下效果最优)

5.2 选择指南

场景 推荐方法 原因
图像像素值(0255 → 01) 归一化 已有明确上下界,无需估计分布参数
神经网络输入 归一化或标准化 两者皆可,取决于具体网络架构和激活函数
使用距离度量的算法(KNN、K-Means) 归一化 限定范围可避免量纲差异主导距离
线性回归 / 逻辑回归 标准化 配合正则化时各特征惩罚均匀
PCA / LDA 降维 标准化 要求零均值输入,否则第一主成分仅反映量纲
数据含异常值 标准化 对异常值更鲁棒
数据近似正态分布 标准化 Z-Score 天然契合正态分布假设

6. Robust Scaling(鲁棒缩放)——异常值场景的替代方案

当数据中存在大量异常值时,归一化和标准化都可能失效。此时可选择 Robust Scaling

$$
x’ = \frac{x - Q_{50}}{Q_{75} - Q_{25}}
$$

其中 $Q_{25}$、$Q_{50}$、$Q_{75}$ 分别为第一四分位数、中位数和第三四分位数(即 IQR)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np
from sklearn.preprocessing import RobustScaler

data = np.array([10, 12, 11, 13, 10, 12, 11, 100], dtype=float).reshape(-1, 1)

scaler = RobustScaler()

# fit:从训练数据中学习参数
scaler.fit(data)

# 查看 fit 学到的参数
print("center_:", scaler.center_) # [11.5] — 中位数 Q50
print("scale_: ", scaler.scale_) # [1.5] — 四分位距 IQR = Q75 - Q25

# transform
data_scaled = scaler.transform(data)
print("结果:", data_scaled.flatten())

# fit_transform 一步到位
# data_scaled = scaler.fit_transform(data)

RobustScaler 使用中位数和四分位距替代均值和标准差,与 StandardScalerMinMaxScaler 相比,受极端异常值的影响最小——这正是 fit 学到不同参数带来的本质差异。

7. 小结

  • 归一化通过线性变换将数据压缩到任意指定区间 $[a, b]$(默认为 $[0, 1]$),适合已知边界的场景,但对异常值非常敏感;
  • 标准化使数据均值为 0、标准差为 1,适合大多数机器学习算法,对异常值相对鲁棒;
  • 数据含较多异常值时,优先考虑 Robust Scaling
  • 两种方法都不改变数据分布的形状,仅进行平移和缩放;
  • 应在划分训练集/测试集之后,仅在训练集上拟合参数($x_{\min}$、$x_{\max}$、$\mu$、$\sigma$),再用这些参数转换测试集,避免数据泄露。