数值特征缩放方法权威指南:原理、场景与局限

2026-06-12阅读 0热度 0
机器学习

数值特征工程在机器学习模型训练中属于不可或缺的预处理步骤。处理数值数据时,特征尺度差异与异常值是两个核心难点。以年龄和薪资为例,两者的数值范围相差数个数量级——若不进行标准化处理,模型往往倾向于给数值较大的特征(如薪资)分配更高权重,从而忽略年龄这类关键信息。

偏斜分布则是另一项常见挑战。许多特征的值集中在狭窄区间内,却夹杂着少量极端值。例如“兄弟姐妹数量”这一特征,绝大多数样本落在0到2之间,偶尔出现的8或10会严重扭曲整体分布。直接剔除这些极端样本虽简单,但多数情况下这些异常值承载着真实业务信息,不应简单丢弃。

解决上述问题的常用方法包括四种:标准化(Standardization)、Robust缩放(Robust Scaler)、幂变换(Power Transformer)、归一化(Normalization)。接下来借助scikit-learn内置的California住房数据集进行实操演示,重点关注“Median Income”和“Population”这两个量级截然不同的特征:

 dataset = fetch_california_housing()  
 X_full, y_full = dataset.data, dataset.target  
 feature_names = dataset.feature_names  
 df = pd.DataFrame({  
     "MedInc": X[:, 0],  
     "Population": X[:, 4],  
 })  
 df.describe()
 +---------+------------+-------------+  
| Metric  |   MedInc   | Population  |  
+---------+------------+-------------+  
| count   |     20640  |       20649 |  
| mean    |  3.870671  | 1425.476744 |  
| std     |   1.899822 | 1132.462122 |  
| min     |   0.499900 |           3 |  
| 25%     |   2.5634   |         787 |  
| 50%     |     3.5348 |        1166 |  
| 75%     |   4.743250 |        1725 |  
| max     |    15.0001 |       35682 |  
 +---------+------------+-------------+

首先观察原始数据(未经任何缩放或变换)的散点图,分别展示包含异常值以及剔除异常值(仅保留第0至第99百分位)后两种情形:

 X = X_full[:, [0,4]]  

outlier_range = (0, 99)  
cutoffs_median_inc = np.percentile(X[:, 0], outlier_range)  
cutoffs_population = np.percentile(X[:, 1], outlier_range)  

non_outliers = np.all(X > [cutoffs_median_inc[0], cutoffs_population[0]], axis=1) & np.all(  
        X < [cutoffs_median_inc[1], cutoffs_population[1]], axis=1  
    )  
non_outlier_X = X[non_outliers]  
non_outliers_Y = y_full[non_outliers]  

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))  
fig.suptitle('Original Data')  
ax1.set_title('Full Data')  
ax1.scatter(X[:, 0], X[:, 1], c=y_full)  
ax1.set_xlabel('MedInc')  
ax1.set_ylabel('Population')  

ax2.set_title('Non-outlier Data')  
ax2.scatter(non_outlier_X[:, 0], non_outlier_X[:, 1], c=non_outliers_Y)  
ax2.set_xlabel('MedInc')  
ax2.set_ylabel('Population')  
 plt.show()

接下来逐一演示上述四种技术如何改变数据形态。

标准化(Standardization)

标准化的核心目标是将数值特征调整到均值为0、方差为1的尺度。举例来说,年龄相差10岁,收入却可能相差50k——对模型而言,收入的信号强度远超年龄。通过标准化,所有特征被映射到统一的均值和方差上,从而具备可比性。

z分数的计算公式为:

z = ( x — mean ) / standard_deviation.

标准化后的特征更适合那些假设输入分布接近正态的算法,例如线性回归、逻辑回归、支持向量机、PCA等降维方法。Scikit-learn中对应的实现是StandardScaler:

 standard_scaler = StandardScaler()  
 standardized_x = standard_scaler.fit_transform(X)

原始数据中Population的取值范围是0到35k,MedInc为0到14。标准化后两者分别缩放到[0,35]和[-2,6]区间,量级上已可比较。但标准化有一个显著缺陷:对异常值极其敏感。从图中可见,最大值虽从35k压缩到约30,但由于异常值拉高了均值,大部分数据被挤压到[-1,4]的狭窄区间内。换言之,标准化仅改变数值尺度,并不改变分布形状——数据原本偏斜,标准化后依然偏斜。不过两个特征的主体数据确实落入了可比较的范围:MedInc集中在[-2,4],Population集中在[-1,4]。

Robust缩放(Robust Scaler)

RobustScaler是标准化的变体,其核心差异在于使用中位数和四分位距(IQR,通常取第25至第75百分位)替代均值和标准差。标准化面对极端异常值时,均值会被拉高、方差被放大,导致缩放效果大打折扣。而IQR只关注中间50%的数据,少数极端值对其影响微乎其微。异常值本身不会被移除,特征中仍保留着极端样本,但主体数据会落在更合理的区间内。

 roubust_scaler = RobustScaler(quantile_range=(25.0,75.0),  
     with_scaling=True, with_centering=True, unit_variance=True)  
 robust_x = roubust_scaler.fit_transform(X)

默认分位数范围(25,75)意味着两端各忽略25%的极端数据,这正是“鲁棒”二字的由来。

图中显示,两个特征的主体数据落在相近区间:MedInc在[-2,5],Population在[-2,6]。与标准化相比,Robust缩放对异常值的抵抗能力更强,但本质上仍是线性变换——无法根除异常值带来的分布偏斜。要解决这一问题,需要引入非线性变换,如对数变换、幂变换、分位数变换等。

幂变换(Power Transformer)

收入、房价等现实数据通常呈现一个共同模式:大量值集中在较低区间,同时存在少数极大的异常值。线性回归或逻辑回归试图找到一条使所有数据点距离最小的拟合线,一个极端异常值就像跷跷板一端的重物,足以将整条线拽偏,破坏对其余样本的拟合。神经网络虽对数据形态容忍度较高,但某个极端值在单次训练步中产生的梯度冲击,结合较大的学习率,同样可能引发损失曲面的剧烈震荡。

PowerTransformer通过压缩分布的长尾,将异常值拉近数据主体,将偏斜分布整形为接近钟形曲线。异常值的信息得以保留,但不再以极端数值扭曲模型。Scikit-learn中除了PowerTransformer,QuantileTransformer也可达到类似效果。

先用箱线图直观展现Population特征的长尾:

  plt.figure(figsize=(12, 4))  
 sns.boxplot(x=df['Population'], color='skyblue')  
 plt.title('Box Plot of Population (Visualizing Outliers)')  
 plt.xlabel('Population Value')  
 plt.axvline(1425, color='orange', linestyle='--', label='Mean: 1425')  
 plt.legend()  
 plt.show()

箱体对应数据主体(四分位距范围),右侧那一长串散点正是可能“掀翻跷跷板”的极端Population值。

对Population应用PowerTransformer:

 from sklearn.preprocessing import PowerTransformer  
   
 pt = PowerTransformer(method='yeo-johnson')  
 pt_transformed = pt.fit_transform(X[:,[1]])

绘制变换前后的直方图对比:

 import matplotlib.pyplot as plt  
import seaborn as sns  
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))  
sns.histplot(standardized_x[:,1], ax=ax1)  
ax1.set_title("Before: Standardized Population (Skewed)")  
ax1.set_xlabel("Value")  
sns.histplot(pt_transformed[:,0], ax=ax2)  
ax2.set_title("After: PowerTransformed Population (Normal-like)")  
ax2.set_xlabel("Transformed Value")  

plt.tight_layout()  
 plt.show()

效果一目了然:PowerTransformer成功将原本右偏的分布变换为接近正态的形状。

再看变换前后的箱线图:标准化后的数据主体仍然偏左,长尾向右延伸;PowerTransformer处理后,箱体居中,两侧须线基本对称。

 fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))  
sns.boxplot(x=standardized_x[:,1], ax=ax1)  
ax1.set_title('Standardized Populationn(Scale changed, outliers remain)', fontsize=13)  
ax1.set_xlabel('Z-Score')  
sns.boxplot(x=pt_transformed[:,0], ax=ax2)  
ax2.set_title('PowerTransformed Populationn(Shape changed uniform tails)', fontsize=13)  
ax2.set_xlabel('Transformed Value')  

plt.tight_layout()  
 plt.show()

左图(标准化)中数值分布跨度很大。线性回归一旦在异常值上产生错误预测,平方误差会被放大到极端量级,拟合线被迫朝异常值方向偏移,整体拟合质量随之下降。右图(幂变换)中异常值与主体数据的距离大幅缩短,误差分布更加均匀,模型得以将注意力集中在数据主体上。

对比标准化后的MedianInc和经过PowerTransformer处理的Population:

与标准化不同,异常值被拉入数据主体的邻域。数据分布均匀,没有被压缩到狭窄区间。在MedianInc最高的第6档中,Population的取值分散在[-4, 2]之间,模型能够捕捉到这些细微差异并发现特征间的关联。

归一化(Normalization)

归一化将所有数据重新缩放到0-1的范围。KNN等基于距离的算法对数值绝对大小敏感,归一化对这类算法尤为重要。在神经网络中,归一化还能缓解梯度消失问题。较大的输入值(例如年龄为99)容易使激活函数进入饱和区,梯度趋近于零,权重不再更新,学习就此停滞。将输入缩放到0-1之间,恰好落在多数激活函数的敏感区域内。

最常用的归一化方法是Min-Max缩放,公式为:

x_norm = (x — x_min) / (x_max — x_min).

Min-Max缩放有一个致命弱点:一旦出现极端异常值——例如某人的收入为10亿美元——它会被映射为1,其余所有正常值全部被压缩到接近0的微小区间内,数据中的细微差异被彻底抹平。看看归一化对当前数据集的实际效果:

 min_max_scaler = MinMaxScaler()  
 nomralize_x = min_max_scaler.fit_transform(X)

Min-Max缩放将Population的最大值映射为1.0,而几乎全部数据都被挤压到0-0.16的区间内。回顾前面的箱线图——Population最大值达到35k,数据主体集中在1000-2000之间。35k被映射为1后,1000-2000这个区间仅能占据1/35的宽度,有意义的分辨率荡然无存。归一化最适合的场景是输入特征的边界已知且固定,典型例子是RGB图像的像素值——取值范围恒定在0-255。

下表汇总了四种缩放器的适用场景:

 .----------------------.---------------------------.-------------------------------------------------------.  
|        Issue         |         Best Tool         |                         Why?                          |  
:----------------------+---------------------------+-------------------------------------------------------:  
| Different Scales     | StandardScaler            | Makes features comparable.                            |  
:----------------------+---------------------------+-------------------------------------------------------:  
| Hea vy Skew           | Power/QuantileTransformer | Normalizes the distribution shape.                    |  
:----------------------+---------------------------+-------------------------------------------------------:  
| Extreme Outliers     | RobustScaler              | Uses Median and IQR, unaffected by marginal outliers. |  
:----------------------+---------------------------+-------------------------------------------------------:  
| Neural Network Input | Min-Max Scaler            | Matches the "expected" range of neurons.              |  
 '----------------------'---------------------------'-------------------------------------------------------'

使用这些缩放器时有一条铁律:fit() 只在训练数据上调用。fit():计算统计量(均值、标准差等),只能在训练集上执行。transform():用已有的统计量做变换,训练集、测试集、线上数据都要执行。如果在测试集上调用了fit,等于模型提前“看到”了测试数据的分布——这就是数据泄露。部署模型时,缩放器的参数也必须一起打包上线。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策