特征工程入门:特征提取、特征选择、特征变换

特征工程,说白了就是让数据变得更好用。我做了这么多年算法,见过不少项目在模型上死磕调参,结果效果还不如别人把特征好好洗一遍。你想想看,模型能学到什么,很大程度上取决于你喂给它的特征长什么样。

这个章节咱们就聊三个最基本的动作:提取、选择、变换。它们分别解决不同的问题——「有没有」、「好不好」、「对不对」。我把这三步串联起来,就是一套完整的特征加工流程。

特征工程核心流程 原始数据 特征提取 特征选择 特征变换 模型训练 评估后回溯迭代 文本/时间/组合 过滤/包裹/嵌入 缩放/PCA/编码

一、特征提取

特征提取,就是从原始数据里「挖」出新特征。原始数据往往不是直接能用的格式。比如一段文本、一个时间戳、一串日志。你需要把它们转成数值。我早期做电商推荐时,用户行为日志全是字符串,根本喂不进模型。后来学会把「浏览时长」「点击次数」「加购间隔」这些信息抽出来,模型效果一下子就上去了。

常见场景我列一下:

数据类型提取方法典型输出
文本TF-IDF / Word2Vec高维稀疏向量
时间戳分解为年/月/日/星期/小时多个数值列
图像边缘检测 / 颜色直方图特征向量
日志序列滑动窗口统计量均值、方差、趋势

举个例子。假设你有一个时间戳字段 2024-12-01 14:35:20,直接扔给模型它看不懂。我一般会这么拆:

import pandas as pd

ts = pd.to_datetime('2024-12-01 14:35:20')
features = {
    'year': ts.year,
    'month': ts.month,
    'day': ts.day,
    'hour': ts.hour,
    'weekday': ts.weekday(),
    'is_weekend': 1 if ts.weekday() >= 5 else 0,
    'quarter': ts.quarter
}
我的小技巧: 提取特征时,优先关注和业务逻辑直接相关的。比如分析销售数据,「是否是促销日」往往比「星期几」有用得多。

二、特征选择

特征多了,不一定就好。我见过一个团队把特征做到 2000 维,结果模型训练慢,还过拟合。特征选择的任务,就是帮你砍掉冗余、噪声和不相关的特征。

常用的方法分三类。我习惯把它们列成一个对比表,方便选型:

方法核心思路优缺点
过滤法统计指标筛选(卡方、互信息、方差)快,但忽略特征间交互
包裹法用模型效果评估特征子集(RFE)效果好,计算成本高
嵌入法模型自带特征权重(L1正则、树模型重要性)折中方案,推荐优先试

举个例子,使用卡方检验过滤文本分类特征:

from sklearn.feature_selection import SelectKBest, chi2
from sklearn.feature_extraction.text import CountVectorizer

# 假设已有文本数据 X_text 和标签 y
vec = CountVectorizer(max_features=2000)
X_bow = vec.fit_transform(X_text)

selector = SelectKBest(chi2, k=300)
X_selected = selector.fit_transform(X_bow, y)
注意: 我曾经吃过一次亏。做高维特征选择时,直接对所有特征用了卡方检验,结果忽略了类别不平衡问题。后来加了分层采样,选出来的特征才算靠谱。特征选择不能脱离数据分布。

三、特征变换

特征变换,就是改变特征的「数值形态」或「空间结构」。目的很明确:让模型更容易拟合。说白了,就是消除量纲影响、处理长尾分布、或者降维。

我平时用得最多的几个:

  • 归一化(Min-Max Scaling): 把数据压缩到 [0,1] 区间。适合边界明确的场景。
  • 标准化(Z-score): 转化为均值为0、标准差为1。适合大多数树模型以外的场景。
  • 对数变换: 拉近长尾分布。我处理用户消费金额时经常用。
  • PCA: 线性降维,保留主要信息。

代码实现很简单:

from sklearn.preprocessing import StandardScaler, MinMaxScaler
import numpy as np

data = np.array([[100], [200], [300], [1000], [5000]])

# 标准化
scaler = StandardScaler()
std_data = scaler.fit_transform(data)

# 对数变换(先取log再标准化)
log_data = np.log1p(data)
log_std = scaler.fit_transform(log_data)
要点: 特征变换的顺序有讲究。通常先做提取和选择,再做变换。如果先变换再选择,可能会丢失有区分度的信息。我建议把变换放在流水线的最后一步。

四、三步协同流程

前面三个步骤,在实际项目里不是串行走一遍就完事的。它们之间会互相影响。比如说,你做了特征选择之后发现效果不好,可能需要回到提取阶段再挖一些新特征。或者变换之后方差变小了,原来能选上的特征又被筛掉了。

我自己的习惯是这样组合:

  1. 粗提取 —— 先快速从原始数据里拿到一批基础特征,不要太完美,够用就行。
  2. 初筛 —— 用过滤法或树模型重要性做一次快速筛选,把明显没用的砍掉。
  3. 变换+精筛 —— 对剩余特征做标准化或对数变换,再用包裹法或嵌入法做二次选择。
  4. 迭代 —— 看模型表现,决定是否回到第一步。

这个流程我在好几个项目里实践过,稳得很。尤其是遇到特征量超过 1000 的数据集,这套方法能把时间从半天压缩到一小时以内。