2026 AI 打卡 Day6:特征工程之数值特征工程从零到精通(6大技巧 + Pipeline + 完整代码)
目录
一、为什么数值特征工程最重要?
在机器学习中,“垃圾进,垃圾出” 是铁律。
数值特征(Age、Fare、SibSp 等连续数字)占了数据 70% 以上,但原始数据往往有缺失值、异常值、尺度不一、非线性等问题。
处理好数值特征,模型效果能直接提升 10-50%!
(Kaggle Titanic 比赛中,很多选手就是靠数值特征处理从 0.78 冲到 0.85+)
我从零基础开始,用 Titanic 数据集 一步步实践,记录了完整笔记。现在把全流程 + 6个独立Demo + 最终Pipeline + Markdown笔记 整理成这篇博客,供大家直接复制使用。
二、 六大核心技巧一览表(最重要!)
三、6大核心技巧详解(每个都有完整Demo)
1. 标准化(StandardScaler)
该类是什么特征:
数值特征(连续型数字,如年龄、票价)
做什么:
把所有数值转换成均值=0、标准差=1的分布,让不同尺度特征在同一水平线上
为什么选这个特征:
Age(0-80)和Fare(0-65)尺度完全不同,标准化后模型(线性回归、神经网络、KNN)不会被大数字“欺负”,效果提升明显
# -*- coding: utf-8 -*-
# demo_01_StandardScaler.py
import pandas as pd
from sklearn.preprocessing import StandardScaler
df = pd.read_csv('https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv')
features = ['Age', 'Fare']
df[features] = df[features].fillna(df[features].median())
scaler = StandardScaler()
df[['Age_std', 'Fare_std']] = scaler.fit_transform(df[features])
print(df[['Age_std', 'Fare_std']].describe().round(4))

2. 归一化(MinMaxScaler)
该类是什么特征:
数值特征(连续型数字)
做什么:
– 把数值压缩到0~1之间(最小值→0,最大值→1)
为什么选这个特征:
– 神经网络、决策树、距离类算法(如KNN)对0-1范围更敏感,避免某个特征“一家独大”
import pandas as pd
# MinMaxScaler: 归一化器。将所有数值压缩到 $[0, 1]$ 之间。
from sklearn.preprocessing import MinMaxScaler
df = pd.read_csv("../../data/titanic.csv")
print("=== 归一化(MinMaxScaler)Demo ===")
features = ['Age', 'Fare']
df[features] = df[features].fillna(df[features].median()) # 补全缺失值
# 归一化(核心)
scaler = MinMaxScaler()
# fit : 学习阶段。计算数据的最大值(Max)和最小值(Min)。
# transform: 执行阶段。根据算好的 Max/Min 进行数学转换。
# fit_transform 组合拳。一次性完成学习和转换。
df[['Age_mm', 'Fare_mm']] = scaler.fit_transform(df[features])
print("归一化后(0~1范围):")
print(df[['Age_mm', 'Fare_mm']].head())
print("\n最小值和最大值:")
print(df[['Age_mm', 'Fare_mm']].describe().loc[['min', 'max']].round(4))

3.离散化(分箱 / KBinsDiscretizer)
该类是什么特征:
# 数值特征(连续型 → 类别型)
做什么:
– # 把连续数字切成固定几个“箱子”(如0-4),把Age变成“青年/中年/老年”标签
为什么选这个特征:
– 模型更容易学习非线性关系,减少极端值影响,防止过拟合(Kaggle上常用)
核心代码:
from sklearn.preprocessing import KBinsDiscretizer
binner = KBinsDiscretizer(n_bins=5, encode='ordinal', strategy='quantile')
df[['Age_bin', 'Fare_bin']] = binner.fit_transform(df[features]).astype(int)

4. 缺失值填充(SimpleImputer)
该类是什么特征:
# 数值特征(有NaN)
做什么:
– # 用中位数/均值/常数把NaN填满(Age有177个缺失)
为什么选这个特征:
– 模型无法处理NaN,必须先填;中位数最稳健(不受极端值影响)
Demo:
# -*- coding: utf-8 -*-
import pandas as pd
from sklearn.impute import SimpleImputer
df = pd.read_csv("../../data/titanic.csv")
print("=== 缺失值填充Demo ===")
print("填充前Age缺失值数量:", df['Age'].isnull().sum())
# 中位数填充(最推荐)
imputer = SimpleImputer(strategy='median')
df['Age_filled'] = imputer.fit_transform(df[['Age']])
print("填充后缺失值数量:", df['Age_filled'].isnull().sum())
print("填充后Age统计:")
print(df['Age_filled'].describe().round(2)))

5. 异常值处理(IQR Capping)
该类是什么特征:
# 数值特征(有极端值)
做什么:
– # 把Fare里512元这种超级异常值“压”到合理上限(不删除数据)
为什么选这个特征:
– 极端值会把模型拉歪(尤其是线性模型),capping是最温和有效的处理方式
Demo:
df = pd.read_csv("../../data/titanic.csv")
print("=== 异常值处理(IQR Capping)Demo ===")
# 计算IQR
Q1 = df['Fare'].quantile(0.25)
Q3 = df['Fare'].quantile(0.75)
IQR = Q3 - Q1
upper_limit = Q3 + 1.5 * IQR
print(f"Fare异常值上限:{upper_limit:.2f}")
# capping(超过上限的全部设为上限)
df['Fare_capped'] = df['Fare'].clip(upper=upper_limit)

6. 特征交叉(Cross Feature)
该类是什么特征:
# 数值特征衍生(交叉组合)
做什么:
– # 用Age×Fare、Age/Fare创建新列,捕捉“年龄×财富”这种非线性关系
为什么选这个特征:
– 极端值会把模型拉歪(尤其是线性模型),capping是最温和有效的处理方式
Demo原始特征往往不够强,交叉后模型效果经常提升10-30%(Kaggle神器)
# 先填充缺失值
df['Age'] = df['Age'].fillna(df['Age'].median())
# 创建交叉特征
df['Age_Fare_product'] = df['Age'] * df['Fare'] # 乘法
df['Age_Fare_ratio'] = df['Age'] / (df['Fare'] + 1) # 除法(+1防除0)
df['Age_bin_Fare'] = df['Age'] // 10 * df['Fare'] # 分箱后交叉

四、最佳处理顺序(必须背下来!)
五、工业级 Pipeline(一键处理所有数值特征)
# 01_numerical_pipeline_final.py(已保存 joblib)
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, KBinsDiscretizer, FunctionTransformer
num_pipeline = Pipeline([
('imputer', SimpleImputer(strategy='median')),
('cap_outlier', FunctionTransformer(cap_outliers)),
('binning', KBinsDiscretizer(n_bins=5, encode='ordinal')),
('scaler', StandardScaler())
])
X_train_transformed = num_pipeline.fit_transform(X_train)
joblib.dump(num_pipeline, 'numerical_pipeline.joblib')
六、知识点总结表格
| 序号 | 技巧名称 | 作用(做什么) | 为什么重要(核心价值) | 最佳使用场景 | 核心函数 / 方法 | 注意事项 / 常见坑 |
|---|---|---|---|---|---|---|
| 1 | 标准化 (StandardScaler) |
把数据转换成均值=0、标准差=1 | 不同尺度特征(Age 0-80 vs Fare 0-512)会让模型“偏心”,标准化后所有特征同等重要 | 线性模型、神经网络、KNN、SVM | StandardScaler() |
必须在训练集 fit,测试集只 transform |
| 2 | 归一化 (MinMaxScaler) |
把数据压缩到 0~1 区间 | 神经网络、距离类算法对 0-1 范围最敏感,避免某个特征“一家独大” | 神经网络、决策树、KNN | MinMaxScaler() |
对异常值敏感,先处理异常值再归一化 |
| 3 | 离散化(分箱) (Binning) |
把连续数字切成固定类别(0、1、2、3、4) | 把非线性关系变成“类别”,减少过拟合,模型更容易学习 | 树模型(随机森林、XGBoost)、有极端值时 | KBinsDiscretizer(n_bins=5) |
等频(quantile)比等宽好;箱数 5-10 最佳 |
| 4 | 缺失值填充 | 用中位数/均值/常数填补 NaN | 模型无法处理 NaN,必须先填;中位数最稳健(不受极端值影响) | 任何有缺失值的数值列 | SimpleImputer(strategy='median') |
优先用中位数;不要用均值(易被拉偏) |
| 5 | 异常值处理 (Capping) |
把极端值“压”到合理上限(IQR法) | 极端值(如 Fare=512)会严重拉歪模型分布,导致预测不准 | 有明显长尾分布的特征(Fare最典型) | clip(upper=upper_limit) 或 IQR |
推荐 capping 而不是删除数据 |
| 6 | 特征交叉 | 创建新特征:x*y、x/y、x//10 * y 等 |
捕捉原始特征无法表达的非线性交互关系(年龄×财富) | 几乎所有项目(Kaggle提分神器) | 手动计算或 PolynomialFeatures |
先填充缺失值再交叉;防止除0加+1 |
七、常见坑 & 避坑指南
- ❌ 测试集用了
fit_transform→ 数据泄漏! - ❌ 用均值填充 Age → 必须用中位数
- ❌ 分箱后没
.astype(int)→ 类型错误 - ✅ 所有步骤放 Pipeline 中自动处理
从“只会Python + pandas”到今天跑通6个Demo + Pipeline,我用了不到一周。
特征工程真的比模型重要!
欢迎点赞、收藏、评论,你的一个赞就是我继续更新类别特征的动力!
代码仓库:https://github.com/codeInbpm/ML-Learning-Journey-2025
完整系列:搜索 “ML-Learning-Journey-2025”
下一篇文章预告:类别特征工程全攻略(含WOE编码实战)
你已经迈出了特征工程最重要的一步!🚀
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)