4. 特征缩放:标准化 vs 归一化,到底选哪个
这个问题,面试里出现频率极高。说实话,刚入行那会儿我也被问懵过。记得有一次面试官问:”你什么时候用 StandardScaler,什么时候用 MinMaxScaler?” 我当时脑子里就一个念头——不都是把数据压一压吗?
后来自己做项目做多了才明白,这两兄弟表面看着像,骨子里差别可不小。今天我一次性给你讲清楚。
4.1 先说标准化:StandardScaler
标准化的核心思想很简单:把数据变成均值为0、标准差为1的分布。公式长这样:
z = (x - μ) / σ
x: 原始值
μ: 特征列的均值
σ: 特征列的标准差
处理完之后,数据分布的形状基本不变。原来是正态分布,处理后还是正态分布,只是位置和尺度变了。
我个人的习惯:绝大多数情况下,默认先试 StandardScaler。为什么?
- 它对异常值不那么敏感。虽然异常值会影响均值和标准差,但只要数据量够大,影响有限
- 输出没有固定范围,不会强制把数据塞进[0,1]区间
- 保留了原始分布的形状信息
举个例子,我在做一个用户行为预测项目时,特征的量级差别巨大:”月消费金额”范围是0到50000,”登录次数”是0到100。直接扔进模型,金额特征会把登录次数完全压死。用 StandardScaler 一处理,两者都在同一尺度上,模型才学会”公平”对待每个特征。
4.2 再讲归一化:MinMaxScaler
归一化的目标完全不同:把数据缩放到[0,1]区间。公式是这样的:
X_norm = (X - X_min) / (X_max - X_min)
X_min: 特征列的最小值
X_max: 特征列的最大值
处理后,最大值变成1,最小值变成0,中间值线性映射。
你想想看,这种缩放方式有个致命弱点——对异常值非常敏感。假设一个特征99%的值都在0到100之间,突然有个异常点跑到1000。那99%的值都会被压缩到0到0.1之间,信息损失很大。
4.3 一张表说清楚区别
| 对比维度 | 标准化(StandardScaler) | 归一化(MinMaxScaler) |
|---|---|---|
| 输出范围 | 无固定范围,通常以0为中心,大部分值在[-3,3] | 固定到[0,1]区间 |
| 对异常值敏感性 | 较低,受异常值影响有限 | 极高,单个异常值会严重扭曲正常值的分布 |
| 保留分布形状 | 保留原始分布形状 | 线性拉伸,分布形状不变但位置改变 |
| 适用算法 | 线性回归、SVM、PCA、神经网络等所有需要高斯假设的模型 | KNN、K-Means等基于距离的算法,神经网络输入层 |
| 是否需要新数据重新计算 | 需要保存训练集的μ和σ | 需要保存训练集的min和max |
4.4 具体什么时候用哪个?
我做项目时有一套自己的判断逻辑,分享给你:
优先用 StandardScaler 的场景:
- 数据大致服从正态分布或接近正态分布
- 算法有高斯假设(比如线性回归、LDA、PCA)
- 数据中有异常值,但你不想粗暴地删除它们
- 你不知道该选哪个——先试 StandardScaler 总没错
优先用 MinMaxScaler 的场景:
- 数据有明确的上下界(比如图像像素值0-255)
- 算法对数值范围敏感,需要严格在[0,1]区间(比如神经网络输入层)
- 数据是稀疏的(有很多0值),用 MinMaxScaler 可以保持稀疏性
- 特征间的关系是线性的,需要保持相对距离
4.5 代码来了,直接上例子
说一千道一万,不如跑个代码看看效果。下面这个例子用 scikit-learn 对比两种缩放方法:
from sklearn.preprocessing import StandardScaler, MinMaxScaler
import numpy as np
# 模拟数据:包含一个异常值
data = np.array([[10], [12], [11], [13], [15], [100]]).astype(float)
# 标准化
scaler_std = StandardScaler()
data_std = scaler_std.fit_transform(data)
# 归一化
scaler_mm = MinMaxScaler()
data_mm = scaler_mm.fit_transform(data)
print("原始数据:", data.ravel())
print("标准化后:", data_std.ravel().round(3))
print("归一化后:", data_mm.ravel().round(3))
输出结果很能说明问题:
原始数据: [ 10. 12. 11. 13. 15. 100.]
标准化后: [-0.619 -0.475 -0.547 -0.332 -0.188 2.16 ]
归一化后: [0. 0.022 0.011 0.033 0.056 1. ]
看到了吧?
- 标准化后,大部分正常值都在-0.6到-0.2之间,异常值100被映射到2.16。模型依然能识别出它是异常点
- 归一化后,正常值全被压缩到了0到0.056之间。这5个正常值之间的差异被淹没了,模型基本分不清谁是谁
我之前做过一个特征工程的分享,就用了这个例子。当时台下有人问:”这不正好说明归一化不好吗?” 我说:”不是不好,是要看场景。如果你的业务场景里,异常值本身就是重要的信号,用标准化能保留这个信号。但如果异常值是噪声,你想让模型忽略它,那归一化反而帮你把噪声压扁了。”
4.6 知识结构图:特征缩放全流程
下面这张图总结了特征缩放的完整逻辑。你面试时按照这个思路去讲,清晰又有层次:
4.7 面试追问,再补充几点
面试官问完基本区别后,往往会追加几个问题。我把常见追问和应答思路也整理给你:
问:“如果数据里既有数值特征又有类别特征,怎么缩放?”
我通常的做法是:类别特征做独热编码,数值特征单独缩放。而且缩放要在编码之后做,不然会出问题。编码后的0/1特征本身就是固定范围,不需要再缩放。
问:“缩放后的特征还能还原回去吗?”
能。StandardScaler 和 MinMaxScaler 都有 inverse_transform 方法。不过我在生产环境中不太用这个,因为模型训练时用的就是缩放后的数据,推理时保持一致就行。
问:“逻辑回归为什么要做特征缩放?”
逻辑回归用的是梯度下降优化。如果特征尺度不同,梯度更新的方向会被大尺度特征主导,收敛很慢。缩放后每个特征的梯度量级差不多,收敛就快了,而且更容易找到全局最优解。