特征工程(Feature Engineering)¶
"数据和特征决定了机器学习的上限,而模型和算法只是在逼近这个上限。"
特征工程是机器学习中最重要也最耗时的环节,直接决定了模型性能的天花板。
什么是特征工程?¶
特征工程是把原始数据转化为模型能有效利用的特征的过程。包括数据清洗、特征变换、特征构造和特征选择。
graph LR
A[原始数据] --> B[数据清洗]
B --> C[特征变换]
C --> D[特征构造]
D --> E[特征选择]
E --> F[模型训练]
一、数据清洗¶
缺失值处理¶
| 方法 | 做法 | 适用场景 |
|---|---|---|
| 删除 | 删除含缺失值的行/列 | 缺失比例很小(<5%) |
| 均值/中位数填充 | 用该特征的均值或中位数填充 | 数值型特征,缺失随机 |
| 众数填充 | 用出现最多的值填充 | 类别型特征 |
| 前/后向填充 | 用前/后一个值填充 | 时间序列数据 |
| 模型预测填充 | 用 KNN 或回归模型预测缺失值 | 缺失值与其他特征相关 |
实用建议
- 先分析缺失值的模式:是随机缺失还是有规律地缺失?
- 可以新建一个特征
is_missing(0/1),有时缺失本身就是有用的信息
异常值处理¶
检测方法:
- 3σ 原则:假设数据正态分布,超出 \(\mu \pm 3\sigma\) 的视为异常(覆盖 99.7% 的数据)
- IQR 方法:\(Q1 - 1.5 \times IQR\) 以下或 \(Q3 + 1.5 \times IQR\) 以上的视为异常
- 其中 \(IQR = Q3 - Q1\)(四分位距)
- 箱线图(Box Plot):直接看到异常值
- 散点图:发现偏离整体分布的点
处理方式:
- 删除:确认是错误数据时
- 截断(Clipping):将异常值限制在合理范围内
- 转换:对数变换等可以压缩异常值的影响
- 保留:如果异常值是真实的(如超高收入用户),可能不应该删除
重复值处理¶
直接删除完全重复的行。注意检查是否是"近似重复"(如姓名大小写不同)。
二、特征变换¶
特征缩放(Feature Scaling)¶
为什么需要缩放?
许多算法(如 KNN、SVM、梯度下降)对特征的尺度敏感。如果"年龄"范围是 0-100,"收入"范围是 0-1000000,距离计算会完全被"收入"主导。
| 方法 | 公式 | 结果范围 | 适用场景 |
|---|---|---|---|
| 标准化(Z-score) | \(x' = \frac{x - \mu}{\sigma}\) | 均值 0,标准差 1 | 大多数算法,尤其是假设正态分布的 |
| 归一化(Min-Max) | \(x' = \frac{x - x_{\min}}{x_{\max} - x_{\min}}\) | [0, 1] | 需要固定范围时(如神经网络) |
| MaxAbs 缩放 | $x' = \frac{x}{ | x_{\max} | }$ |
| RobustScaler | \(x' = \frac{x - Q_2}{Q_3 - Q_1}\) | 无固定范围 | 有异常值时(基于中位数和 IQR) |
不需要缩放的算法
决策树和基于决策树的集成方法(随机森林、XGBoost)不需要特征缩放,因为它们基于特征值的排序来分裂,与尺度无关。
类别特征编码¶
将文字类别转化为数字,让模型能处理:
直接给每个类别编一个数字:
问题: 模型可能认为 绿色(2) > 蓝色(1) > 红色(0),但颜色之间实际没有大小关系。
仅适用于: 有自然顺序的特征(如 学历:小学 < 初中 < 高中 < 大学)
为每个类别创建一个二值列:
优点: 不引入虚假的大小关系
缺点: 类别太多时(如城市名,有几百个),维度爆炸
解决方案: 对高基数特征使用目标编码或频率编码
数值特征变换¶
| 方法 | 作用 | 适用场景 |
|---|---|---|
| 对数变换 \(\log(x+1)\) | 压缩右偏分布 | 收入、点击量等长尾数据 |
| 平方根变换 \(\sqrt{x}\) | 温和地压缩分布 | 计数数据 |
| Box-Cox 变换 | 自动找到最优变换 | 使数据尽量接近正态分布 |
| 分箱(Binning) | 将连续值离散化 | 年龄段、收入等级 |
三、特征构造¶
特征构造是特征工程中最需要领域知识和创造力的部分。
常见构造方法¶
| 方法 | 示例 |
|---|---|
| 数学组合 | BMI = 体重 / 身高²;单价 = 总价 / 面积 |
| 时间特征 | 从日期中提取:年、月、日、星期几、是否节假日、是否周末 |
| 统计聚合 | 用户过去 7 天的平均消费、最大消费、消费次数 |
| 交叉特征 | 城市×年龄段、品牌×价格区间 |
| 文本特征 | 文本长度、关键词数量、TF-IDF |
| 多项式特征 | \(x_1^2\), \(x_1 x_2\), \(x_2^2\)(增加非线性) |
实际案例:房价预测
原始特征:面积、卧室数、浴室数、建造年份、邮编
构造新特征:
- 房龄 = 当前年份 - 建造年份
- 每间卧室面积 = 面积 / 卧室数
- 浴卧比 = 浴室数 / 卧室数
- 是否新房 = 房龄 < 5
- 地段均价 = 同邮编区域的历史平均价格
四、特征选择¶
特征太多会导致:维度灾难、训练变慢、过拟合。特征选择帮你留下最有用的特征。
方法分类¶
独立于模型,根据统计指标筛选特征:
| 方法 | 适用场景 | 做法 |
|---|---|---|
| 方差阈值 | 通用 | 删除方差接近 0 的特征(几乎没有变化的特征没用) |
| 相关系数 | 回归 | 选择与目标变量相关系数高的特征 |
| 卡方检验 | 分类 | 检验特征与目标是否独立 |
| 互信息 | 通用 | 衡量特征与目标的依赖程度(可捕获非线性关系) |
优点: 计算快,不依赖模型
缺点: 没有考虑特征之间的组合效果
用模型的性能作为评价标准,通过不断尝试特征子集来选择:
- 前向选择:从 0 个特征开始,逐步添加最有用的特征
- 后向消除:从全部特征开始,逐步删除最没用的特征
- 递归特征消除(RFE):每轮训练模型,删掉权重最小的特征
优点: 考虑了特征组合效果
缺点: 计算量大
特征选择嵌入到模型训练过程中:
- L1 正则化(Lasso):自动将不重要特征的权重压缩为 0
- 树模型的特征重要性:随机森林、XGBoost 等天然给出每个特征的重要性排名
优点: 效率高,兼顾过滤法和包裹法的优点
推荐: 实践中最常用
五、特征工程实战流程¶
graph TD
A[获取原始数据] --> B[探索性分析 EDA]
B --> C{数据有问题?}
C -->|缺失值| D[填充/删除]
C -->|异常值| E[处理异常值]
C -->|数据干净| F[特征变换]
D --> F
E --> F
F --> G[特征构造]
G --> H[特征选择]
H --> I[模型训练]
I --> J{效果好?}
J -->|不好| G
J -->|好| K[完成]
实用技巧¶
特征工程经验法则
- 先看数据再建模:花 80% 的时间理解数据,20% 训练模型
- 从简单开始:先用最基本的特征训练基线模型,再逐步添加复杂特征
- 特征和模型要匹配:线性模型需要手动做特征交叉;树模型能自动处理非线性
- 关注数据泄露:不要用未来的数据构造特征(如用未来的股价预测今天的交易)
- 可解释性很重要:你需要能向别人解释每个特征的含义和为什么它有用