数值特征工程中的四种缩放方法:原理、适用场景与局限性

简介: 数值特征工程是机器学习关键预处理步骤,需应对量级差异(如年龄vs薪资)与异常值/偏斜分布问题。本文详解四种核心方法:标准化(均值0方差1)、Robust缩放(抗异常值)、幂变换(矫正偏斜)、归一化(0-1缩放),并用加州住房数据实操对比效果与适用场景。

数值特征工程是机器学习模型训练中不可跳过的预处理环节。处理数值数据时需要面对两个核心问题:特征的量级差异和异常值。以年龄和薪资为例,两者的数值范围差了好几个数量级,如果不做任何处理模型很可能仅凭数值大小就给薪资分配更高的权重,完全忽略年龄的作用。

偏斜分布是另一个问题。很多特征的值集中在一个很小的范围内,但同时存在少量极端值。比如一个表示兄弟姐妹数量的特征,绝大多数样本的值在 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)

标准化把数值特征变换到零均值、单位方差的尺度上。

年龄相差 10收入相差 50k,这对模型来说,收入的信号远比年龄"响亮"得多。将所有特征标准化为均值 0、方差 1 后,不同特征的数值就落到了同一个可比较的区间内。

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]。

StandardScaler 和 RobustScaler 都能把特征拉到可比较的尺度上,但都无法根本性地消除异常值带来的分布偏斜。要解决这个问题,需要引入非线性变换——对数变换、幂变换、分位数变换都属于此类。

幂变换(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 Population\n(Scale changed, outliers remain)', fontsize=13)  
ax1.set_xlabel('Z-Score')  
sns.boxplot(x=pt_transformed[:,0], ax=ax2)  
ax2.set_title('PowerTransformed Population\n(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 — xmin).

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.                            |  
:----------------------+---------------------------+-------------------------------------------------------:  
| Heavy 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,等于模型提前"看到"了测试数据的分布——这就是数据泄露。部署模型时,缩放器的参数也必须一起打包上线。

https://avoid.overfit.cn/post/740a49988996433ba5410caa6f36dce8

by Aparna Suresh

目录
相关文章
|
4天前
|
人工智能 IDE 编译器
Karpathy的LLM Wiki:一种将RAG从解释器模式升级为编译器模式的架构
Andrej Karpathy提出的LLM Wiki,摒弃传统RAG“每次查询重检索”的模式,转而让大模型将原始资料**编译为结构化、可链接、自更新的Markdown Wiki**,实现知识的持久沉淀与复利增长——Obsidian为IDE,LLM为程序员,Wiki即代码库。
265 7
Karpathy的LLM Wiki:一种将RAG从解释器模式升级为编译器模式的架构
|
2月前
|
自然语言处理 监控 机器人
深入RAG架构:分块策略、混合检索与重排序的工程实现
本文详解RAG系统从Demo迈向生产需攻克的5个关键层级:基础向量检索(Level 1)、智能分块与元数据增强(Level 2)、混合搜索(语义+关键词,Level 3)、交叉编码器重排序(Level 4),以及生产级护栏、评估与兜底机制(Level 5)。强调“不编造、可验证、易诊断”,聚焦真实故障场景与可落地优化。
272 2
深入RAG架构:分块策略、混合检索与重排序的工程实现
|
25天前
|
安全 PHP
PHP 8 实用技巧:让你的代码更优雅高效
PHP 8 实用技巧:让你的代码更优雅高效
|
4月前
|
运维 负载均衡 监控
微服务有哪些优缺点?
微服务将应用拆分为小型独立服务,具备技术异构、弹性好、易部署、可独立扩展等优势,适合复杂系统。但其也带来分布式复杂性、运维难、数据一致性挑战等问题,需权衡团队能力与项目需求后采用。
|
25天前
|
PHP 索引
PHP 技巧:利用数组解包简化代码
PHP 技巧:利用数组解包简化代码
|
2天前
|
机器学习/深度学习 数据采集 人工智能
大模型应用:小样本学习的高性价比:轻量算法做基底,大模型做精修.84
本文提出“轻量算法+大模型”协同的小样本分类新范式:轻量模型(如逻辑回归)快速初筛高置信样本,大模型仅精修低置信疑难样本,实现成本降75%、准确率不损、可解释性增强,破解小样本落地难题。
|
20天前
|
存储 JSON 自然语言处理
大模型应用开发-LangChain框架基础
本文摘要: 文章系统介绍了大模型技术应用与开发的全流程,涵盖云端/本地模型部署、Prompt工程、LangChain框架及RAG项目实战。主要内容包括: 模型部署 阿里云百炼平台API接入与安全配置 Ollama本地模型部署方案 OpenAI兼容SDK的多平台调用方法 Prompt工程 Zero-shot/Few-shot提示技巧 金融文本分类/信息抽取实战案例 JSON数据结构处理与模板设计 LangChain框架 组件化架构:Models/Prompts/Memory/Vectorstores 链式调用
|
26天前
|
人工智能 自然语言处理 Linux
自然语言到可运行代码:OpenClaw技术原理、部署及大模型api配置与工程化应用指南
人工智能在代码生成领域的落地,正在系统性改变软件开发的工作流程。OpenClaw作为一类能够理解自然语言需求并输出完整代码结构的AI辅助工具,已经从概念阶段进入实用阶段。它能够接收用户以日常语言描述的功能需求,自动生成函数、类、接口乃至完整模块,在规范写法、减少重复劳动、提升交付速度方面表现突出。但与此同时,这类工具也存在明确的能力边界与使用前提,需要开发者以理性、审慎的方式接入日常开发流程。本文从技术原理、实际体验、效率价值、职业影响、学习门槛与未来趋势出发,完整呈现OpenClaw的真实定位,并提供2026年阿里云、Windows 11、macOS、Linux四大环境的标准化部署流程,同时
521 0
|
9月前
|
数据采集 存储 算法
终于有人把数据挖掘讲明白了
在大数据时代,许多企业面临一个难题:数据存储量庞大,却难以从中挖掘真正价值。本文深入探讨了数据挖掘的核心概念与实践方法,解析了其与普通数据分析的区别,并通过真实案例展示了如何通过数据挖掘发现隐藏的业务规律。文章还详细介绍了数据挖掘的六个步骤及三大关键点,强调了业务理解与数据质量的重要性,帮助企业在实际应用中少走弯路,真正实现数据驱动决策。
终于有人把数据挖掘讲明白了
|
11月前
|
JSON 数据挖掘 API
小红书笔记评论API接口如何使用
小红书作为生活方式分享平台,评论是用户互动的核心形式。通过小红书笔记评论API接口,开发者可高效获取特定笔记下的评论数据(如内容、昵称、时间、点赞数等),用于舆情分析、用户反馈收集和市场调研。请求参数包括`note_id`、`page`、`page_size`、`timestamp`和`sign`,采用HTTP方式调用,返回JSON格式数据,为业务决策提供数据支持。
下一篇
开通oss服务