sklearn 数据预处理中的归一化(Normalization)
📌 注意:在 sklearn 中,“归一化”(Normalization)通常指 样本归一化(Sample-wise Normalization),即对每一行(每个样本) 进行缩放,使其范数为 1。
而对特征列进行缩放到 [0,1] 或 [-1,1] 的操作,在 sklearn 中称为 缩放(Scaling),如MinMaxScaler
。
核心思想
归一化(Normalization) 是指将每个样本(每行) 缩放,使其满足某种范数约束(通常是 L1 或 L2 范数为 1)。
数学公式(L2 归一化):xnormalized=x∣∣x∣∣2x_{normalized} = \frac{x}{||x||₂}xnormalized=∣∣x∣∣2x
其中 ||x||₂ = sqrt(x₁² + x₂² + ... + xₙ²)
是 L2 范数。
常见范数类型:
范数类型 | 公式 | 说明 |
---|---|---|
'l2' |
sqrt(sum(x_i²)) |
默认,欧几里得范数,最常用 |
'l1' |
`sum( | x_i |
'max' |
`max( | x_i |
✅ 适用场景:
- 文本分类、聚类中 TF-IDF 向量的归一化
- 使用余弦相似度或点积的算法(如 SVM with cosine kernel)
- 神经网络中样本输入需要单位长度时
- 避免样本因“长度”不同导致模型偏向“长”样本
常用函数与类
1. sklearn.preprocessing.Normalizer
对每个样本(行)独立进行归一化。
参数说明:
参数名 | 类型 | 默认值 | 说明 |
---|---|---|---|
norm |
str | 'l2' |
范数类型,可选 'l1' , 'l2' |
copy |
bool | True |
是否复制数据。若为 False ,尝试原地修改(对 numpy 数组有效) |
⚠️
Normalizer
是无状态转换器 —— 它不从数据中学习任何参数,因此.fit()
是空操作,可直接.transform()
。
方法:
.fit(X[, y])
→ 返回self
(无实际拟合操作).transform(X)
→ 对每个样本进行归一化.fit_transform(X[, y])
→ 等价于.transform(X)
.get_feature_names_out(...)
→ 返回特征名(兼容管道)
返回值:
.transform(X)
→ 返回numpy.ndarray
或scipy.sparse matrix
(保持输入类型),形状同输入,数据类型为float64
简单示例代码
from sklearn.preprocessing import Normalizer
import numpy as np
# 创建示例数据(每行是一个样本)
X = np.array([[3.0, 4.0],
[1.0, 1.0],
[0.0, 5.0]], dtype=float)
print("原始数据:")
print(X)
print("原始 L2 范数:", np.linalg.norm(X, axis=1))
# 初始化 L2 归一化器
normalizer_l2 = Normalizer(norm='l2')
# 转换数据(无需 fit,直接 transform)
X_normalized_l2 = normalizer_l2.transform(X)
print("\nL2 归一化后:")
print(X_normalized_l2)
print("L2 归一化后范数:", np.linalg.norm(X_normalized_l2, axis=1)) # 应全为 1.0
# 使用 L1 归一化
normalizer_l1 = Normalizer(norm='l1')
X_normalized_l1 = normalizer_l1.transform(X)
print("\nL1 归一化后:")
print(X_normalized_l1)
print("L1 归一化后 L1 范数:", np.abs(X_normalized_l1).sum(axis=1)) # 应全为 1.0
输出示例:
原始数据:
[[3. 4.]
[1. 1.]
[0. 5.]]
原始 L2 范数: [5. 1.41421356 5. ]
L2 归一化后:
[[0.6 0.8 ]
[0.70710678 0.70710678]
[0. 1. ]]
L2 归一化后范数: [1. 1. 1.]
L1 归一化后:
[[0.42857143 0.57142857]
[0.5 0.5 ]
[0. 1. ]]
L1 归一化后 L1 范数: [1. 1. 1.]
2.使用 preprocessing.normalize 函数(函数式接口)
除了 Normalizer 类,sklearn 也提供函数式接口:
from sklearn.preprocessing import normalize
X_normalized = normalize(X, norm='l2', axis=1) # axis=1 表示按行归一化(样本)
print(X_normalized)
✅ 功能与 Normalizer().transform(X) 完全一致,适合脚本快速使用。
❗ 但不适用于管道(Pipeline),因为没有 .fit() 方法。
在管道中使用示例
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
# 生成示例数据
X, y = make_classification(n_samples=100, n_features=4, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 构建管道:样本归一化 + SVM分类器
pipeline = Pipeline([
('normalizer', Normalizer(norm='l2')), # 样本L2归一化
('classifier', SVC(kernel='linear'))
])
pipeline.fit(X_train, y_train)
score = pipeline.score(X_test, y_test)
print(f"测试集准确率:{score:.4f}")
与其他缩放器对比
方法 | 操作对象 | 是否有状态 | 是否改变分布 | 是否受异常值影响 | 适用场景 |
---|---|---|---|---|---|
Normalizer | 样本(行) | ❌ 无状态 | 是(改变方向) | 是(范数计算) | 文本、余弦相似度 |
StandardScaler | 特征(列) | ✅ 有状态 | 保留形状 | 是 | 通用标准化 |
MinMaxScaler | 特征(列) | ✅ 有状态 | 改变形状 | 是 | 缩放到 [0,1] |
RobustScaler | 特征(列) | ✅ 有状态 | 保留形状 | ❌ 否 | 含异常值数据 |
注意事项
重要提醒:
- Normalizer 是无状态的,训练集和测试集可独立归一化,无数据泄露风险。
- 归一化是样本级操作,不适用于“特征需要相同尺度”的场景(此时应使用 StandardScaler 或 MinMaxScaler)。
- 若某样本全为 0,归一化后仍为 0(避免除零错误,sklearn 自动处理)。
- 对稀疏矩阵友好,归一化后仍保持稀疏性。
总结
在 sklearn 中,归一化(Normalization)特指对每个样本向量进行单位范数缩放,常用于文本处理、相似度计算等场景。核心工具是 Normalizer 类或 normalize() 函数,支持 L1/L2 范数。它与对特征列进行缩放的 StandardScaler、MinMaxScaler 有本质区别,使用时需根据任务目标选择正确的预处理方法。