特征工程基础:提取、选择、降维
做数据项目这些年,我最大的感触就是——数据和特征决定了上限,模型只是逼近这个上限。说白了,你拿一堆原始日志直接塞进XGBoost,效果往往还不如人家精心构造几个比率特征后拿线性回归。今天我们就来聊聊特征工程的三个核心动作:提取、选择、降维。
一句话总结三者的分工:
- 特征提取:从原始数据里“变”出新特征(文本→词频、时间→星期)
- 特征选择:从现有特征堆里“挑”出有用的(过滤、包裹、嵌入)
- 特征降维:把高维特征“压缩”到低维空间(PCA、t-SNE)
1. 特征提取 – 从原始数据中创造信息
特征提取,说白了就是把非结构化或半结构化的数据,转化成数值向量。举个最典型的例子:文本数据。你拿到一堆客户评论,计算机不认识汉字,你必须把它变成数字。我个人最喜欢的入门方式就是 TF-IDF。
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = [
"这个产品性价比很高",
"质量太差,用了三天就坏了",
"物流很快,包装也不错"
]
vectorizer = TfidfVectorizer(max_features=100)
X = vectorizer.fit_transform(corpus)
print(X.shape) # (3, 100)
你可能会问:为什么不用简单的词袋(CountVectorizer)?我在一个用户满意度预测项目里踩过坑——直接用词频,结果“的”、“了”这些高频停用词把重要信号淹没了。换成TF-IDF后,模型AUC直接提升了4个点。
除了文本,时间序列特征提取也很常见。比如计算滑动窗口均值、标准差、差分、傅里叶变换。我记得有一次做电商购买间隔预测,我把原始时间戳转成了“距上次购买天数”、“最近7天购买频次”等特征,效果比直接扔时间戳好太多。
经验之谈:特征提取时,尽量保持业务可解释性。不要为了提特征而提特征,比如瞎拼凑高阶多项式。我在信贷风控项目中见过有人把“收入”和“年龄”相乘得到一个新特征,结果模型过拟合得一塌糊涂。
2. 特征选择 – 去芜存菁
特征多了未必是好事。我遇到过几十万维度的特征,全放进去模型训练慢不说,还容易过拟合。特征选择帮你砍掉冗余和无关的特征,提升泛化能力。
常用的三类方法:
| 类别 | 原理 | 典型方法 | 适用场景 |
|---|---|---|---|
| 过滤法 | 统计指标打分,与模型无关 | 卡方检验、互信息、方差阈值 | 特征量极大,快速筛选 |
| 包裹法 | 用目标模型评估特征子集 | 递归特征消除(RFE) | 特征较少,精度要求高 |
| 嵌入法 | 模型自身输出特征重要性 | L1正则(Lasso)、树模型 feature_importances_ | 特征较多,训练可接受 |
我个人的习惯:先拿过滤法快速砍掉明显低相关的特征,比如方差接近0的列。然后再用嵌入法(比如LightGBM的feature importance)选出Top-K。最后如果时间允许,再用包裹法微调。这样做下来,项目节奏又快效果又稳。
# 过滤法示例:方差阈值
from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold(threshold=0.01)
X_selected = selector.fit_transform(X)
print(f"原始维度: {X.shape[1]}, 保留维度: {X_selected.shape[1]}")
注意一点:过滤法和包裹法的组合使用,我曾经在一个电商CTR预估项目里吃过亏——先用卡方过滤到2000维,再用递归特征消除,结果卡方把一些虽然方差小但对埋点事件很敏感的特征给干掉了。建议你过滤法留的阈值宽一点,别太狠。
避坑指南:千万不要在特征选择前看一眼模型性能就拍脑袋定阈值。要结合交叉验证,否则容易陷入“假信号”陷阱。
3. 特征降维 – 压缩不丢失结构
降维和特征选择不同。选择是“挑”,降维是“变”。PCA将原始特征线性组合成新特征,t-SNE更关注高维空间中的局部邻居关系。
我常用的三个工具:
- PCA:线性降维,适合数据可视化、去噪。我在做基因表达数据时,几万个基因用PCA降到50维,分类效果反而更好,因为去掉了噪声。
- LDA:有监督降维,最大化类间距离。适合分类问题。
- t-SNE / UMAP:非线性降维,主要用来可视化,不适合作为建模输入。
from sklearn.decomposition import PCA
pca = PCA(n_components=0.95) # 保留95%方差
X_pca = pca.fit_transform(X_scaled)
print(f"降维后维度: {X_pca.shape[1]}")
这里有个容易翻车的细节:PCA是基于方差的,所以特征必须标准化。否则一个数值范围大的特征就会主导主成分。我曾有一次忘了标准化,结果PCA的前两个主成分几乎全被“年龄”这个变量决定了,完全不表达数据结构。嗯,从那以后再也不敢跳过 preprocessing。
技巧:遇到稀疏高维数据,比如文本TF-IDF特征,PCA效果往往不好。可以试试截断SVD(TruncatedSVD),它不需要先稠密化。
4. 三者的关系与选择策略
很多同学会把这三个步骤搞混,甚至串在一起用。其实它们各有侧重,可以组合,但顺序有讲究。我画了一张我日常用的决策流程图:
我一般遵循两条原则:
- 特征数量百万级以上 → 先特征选择(过滤法快速砍),再考虑是否降维。
- 特征少但噪声大 → 直接上PCA或LDA去噪,降维后再建模。
如果你既做选择又做降维,记得先选择再降维。否则降维后的新特征很难解释,选择也失去了意义。
曾经踩过的坑:有一次我在文本分类项目中,先做了PCA降到100维,再用递归特征消除。结果RFE把所有主成分都保留了,等于白干。顺序错了,耗费大量算力还毫无收益。
好了,特征工程的基础三件套就聊到这儿。不管是用深度学习还是传统模型,这三步都是绕不开的硬功夫。你可以在自己的项目里多试试不同组合,慢慢就会形成自己的套路。