4. 数值型特征标准化与归一化归纳总结

说到特征工程里的标准化和归一化,我估计不少同学第一反应就是“把数据缩到0~1之间”。嗯,其实没那么简单。我刚开始做信用评分模型时,也犯过这种“一刀切”的错。后来被坏特征狠狠教训过一次,才彻底搞明白这两兄弟到底怎么用。

4.1 标准化 vs 归一化:本质区别

先说结论:标准化(Standardization)和归一化(Normalization)都做“缩放”,但目标不同。

  • 标准化:把数据转换成均值为0、标准差为1的分布。说白了就是让数据“中心化”并“压扁”,保留原始分布的形态(偏态、峰度等)。
  • 归一化:把数据线性压缩到某个固定区间(比如[0,1]或[-1,1])。它会改变原始分布的形状——因为缩放范围是固定的。

我在一次信贷审批模型项目中,用了Min-Max归一化对收入做处理。结果模型在测试集上泛化很差——因为新来的客户收入分布跟训练集不同,但归一化硬生生把极值压到一起,导致模型误判。后来换成标准化,稳定性好多了。

方法公式输出范围受异常值影响适合场景
Z-score 标准化z = (x - μ) / σ≈[-3,3](理论无界)中等(均值/标准差被极端值拉动)数据近似正态、需要保留分布形态
Min-Max 归一化z = (x - min) / (max - min)[0,1]极大(极值决定范围)分布固定、无异常值的场景
MaxAbs 归一化z = x / |max|[-1,1]大(受最大绝对值控制)稀疏数据、符号有意义的特征
Robust 标准化z = (x - median) / IQR≈[-3,3]小(用中位数和四分位距)数据存在较多异常值
关键原则:标准化不改变分布形态,归一化会改变。如果你的模型依赖分布假设(如线性回归、逻辑回归),选标准化;如果你只关心相对顺序且无异常值,归一化也能用。

4.2 信用评分中的实战选择

信用评分特征里,最常见的数值型特征有:年龄、收入、贷款金额、历史逾期次数、信用额度使用率等。这些特征的量纲差异巨大——收入可能是几千到几十万,逾期次数最多几十次。如果不做缩放,模型会被大数值特征主导。

我个人习惯按以下三步判断:

  1. 先看分布:画个直方图或箱线图。如果有明显异常值(比如收入出现极端高的富豪),优先用Robust标准化。
  2. 再看模型:树模型(GBDT、XGBoost)对缩放不敏感,可以不做。但线性模型、SVM、KNN、PCA 必须做。
  3. 最后看业务含义:比如“信用额度使用率”本身就在[0,1]区间,归一化后依然是[0,1],标准化反而会变成有正有负——解释性变差。这种情况下归一化更自然。
小技巧:如果你不确定用哪种,可以都试试。在验证集上看指标变化。我见过有些团队只在Pipeline里放StandardScaler,从来没想过换——其实RobustScaler在真实数据上往往效果更好。

4.3 代码实现范例

下面给出sklearn中的四种方法,以及一个简单的对比输出。注意,代码里我故意混入一些异常值——模拟真实信用数据。

import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler, MinMaxScaler, MaxAbsScaler, RobustScaler

# 模拟信用评分特征:年龄、收入、逾期次数、使用率
np.random.seed(42)
ages = np.random.randint(22, 65, 200)
incomes = np.random.normal(8000, 3000, 200)
overdues = np.random.poisson(2, 200)
util_rate = np.random.beta(2, 5, 200)

# 故意加入异常值
incomes[0] = 50000
overdues[5] = 50

data = pd.DataFrame({
    'age': ages,
    'income': incomes,
    'overdue': overdues,
    'util_rate': util_rate
})

# 同时应用四种缩放
scalers = {
    'StandardScaler': StandardScaler(),
    'MinMaxScaler': MinMaxScaler(),
    'MaxAbsScaler': MaxAbsScaler(),
    'RobustScaler': RobustScaler()
}

results = []
for name, scaler in scalers.items():
    scaled = scaler.fit_transform(data)
    results.append({
        '方法': name,
        'income_min': scaled[:, 1].min(),
        'income_max': scaled[:, 1].max(),
        'income_mean': round(scaled[:, 1].mean(), 4)
    })

pd.DataFrame(results).round(4)

你看,同样一个收入特征(异常值50000),MinMaxScaler会把大部分数据压缩到0~0.1之间,而StandardScaler的均值依然接近0,RobustScaler受异常干扰最小。

4.4 避坑指南:标准化后还能解释特征吗?

我曾经犯过一个错:标准化之后,把特征直接丢进线性回归,然后拿着系数说“年龄每增加1个单位,违约概率增加0.02”——实际上标准化后的“1个单位”是1个标准差,不是1岁。所以标准化后的模型系数不能直接用在业务解释上。如果你需要解释性,要么用原始单位做标准化前的模型,要么用归一化(保留原尺度)后再除以原始标准差。

注意:标准化和归一化的参数(均值、标准差、最小值、最大值)必须只在训练集上计算,然后应用到测试集。千万不能在全体数据上fit再split,否则会造成数据泄露——测试信息流入训练,模型性能会虚高。我在验证时就被这个坑过,上线后效果直接崩盘。

4.5 一张图理清所有关系

下面这张SVG图总结了四种缩放方法对同一组数据(含异常值)的影响。我画成了分布变化示意图,方便你在脑子里建立直观印象。

四种缩放方法对数值特征的影响对比 原始数据 多个特征 量纲差异大 含异常值 Z-score 标准化 均值为0,标准差为1 保留分布形态 异常值影响中等 Min-Max 归一化 缩放到[0,1] 改变分布形状 异常值影响极大 MaxAbs 归一化 缩放到[-1,1] 适用于稀疏数据 对符号敏感 Robust 标准化 中位数±IQR 抗异常值能力强 适合真实业务数据 选型建议 • 树模型:可省略缩放 • 线性模型:必须缩放 • 有异常值:优先Robust • 无异常值:Standard或MinMax • 稀疏数据:MaxAbs

4.6 标准化与归一化的统一框架

其实所有方法都可以看作一个线性变换:new_x = (x - loc) / scale。区别只在于loc和scale用什么统计量。

方法locscale抗异常
StandardScalermeanstd弱
MinMaxScalerminmax - min极弱
MaxAbsScaler0|max|弱
RobustScalermedianIQR强

理解了这一点,你甚至可以自己造一个缩放器——比如用分位数间隔或极值截断后再缩放。信用评分中我就曾用过“截断99%分位数后做Min-Max归一化”,效果比纯Robust还好。不过这属于高级技巧,后面讲异常值处理时会再展开。

提醒一句:在Pipeline里一定要记住fit_transform用在训练集,transform用在测试/新数据。很多新手写成fit_transform(test),模型会学到未来信息。我当年就是这么被导师骂的……

好了,这一章的核心就是:不要盲目用任一方法。先看分布,再看模型,最后考虑业务解释。如果你能把这个流程内化成肌肉记忆,信用评分特征筛选的第一步就稳了。