机器学习特征选择:方法与实战技巧
1. 特征选择在机器学习中的核心价值
在真实业务场景中,我们常常会遇到包含数百甚至数千个特征的数据集。去年我参与的一个电商用户行为分析项目,原始数据集包含1368个特征,但最终我们只保留了其中的47个。这个决策使得模型训练时间从4小时缩短到18分钟,准确率反而提升了12%。这就是特征选择的魔力。
特征选择本质上是一个降维过程,但它与PCA等降维技术有本质区别。PCA是通过数学变换创建新的特征维度,而特征选择是从原始特征中筛选出最有价值的子集。这就像在装修房子时,PCA是把旧家具重新改装成新样式,而特征选择是直接扔掉没用的家具。
重要提示:特征选择应该在任何特征工程步骤之后进行,但在最终模型训练之前完成。这个顺序错误是新手最常见的误区之一。
2. Scikit-Learn中的特征选择方法论
2.1 过滤式方法(Filter Methods)
过滤式方法像是特征选择的"初筛"阶段,它们计算速度快,不依赖具体模型。最常用的指标包括:
- 方差阈值:我常用0.8作为阈值,移除方差过低的特征
- 卡方检验:特别适合文本分类任务
- 互信息:能捕捉非线性关系,计算成本略高
from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold(threshold=0.8)
X_reduced = selector.fit_transform(X)
2.2 包裹式方法(Wrapper Methods)
RFE就是典型的包裹式方法,它像是一个"精挑细选"的过程。在实际项目中,我发现这些经验很有用:
- 对于中小型数据集(特征数<1000),RFE效果显著
- 建议先用线性模型作为基模型,再换用目标模型
- 特征排名比二值化的support_更值得关注
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import RFE
# 先用逻辑回归初筛
rfe_lr = RFE(estimator=LogisticRegression(), n_features_to_select=50)
X_lr = rfe_lr.fit_transform(X, y)
# 再用目标模型精筛
rfe_rf = RFE(estimator=RandomForestClassifier(), n_features_to_select=20)
X_rf = rfe_rf.fit_transform(X_lr, y)
2.3 嵌入式方法(Embedded Methods)
这类方法将特征选择作为模型训练的一部分。L1正则化(Lasso)是最典型的代表,但我要特别推荐基于树模型的特征重要性:
from sklearn.ensemble import ExtraTreesClassifier
model = ExtraTreesClassifier(n_estimators=500)
model.fit(X, y)
# 绘制特征重要性
import matplotlib.pyplot as plt
plt.barh(range(len(model.feature_importances_)), model.feature_importances_)
plt.yticks(range(len(feature_names)), feature_names)
plt.show()
3. 工业级特征选择实战技巧
3.1 特征稳定性评估
在金融风控项目中,我发现一个致命问题:每周特征重要性排名波动很大。后来我们引入了稳定性指数:
from sklearn.utils import resample
stability_scores = []
for _ in range(100):
X_sample, y_sample = resample(X, y)
model.fit(X_sample, y_sample)
stability_scores.append(model.feature_importances_)
stability = np.std(stability_scores, axis=0)
3.2 高基数类别特征处理
当遇到像"用户ID"这样的高基数特征时,我的经验是:
- 先做目标编码(Target Encoding)
- 再计算该特征与目标的互信息
- 最后用聚类将相似类别合并
from category_encoders import TargetEncoder
from sklearn.cluster import KMeans
encoder = TargetEncoder()
X_encoded = encoder.fit_transform(X[['category']], y)
mi = mutual_info_classif(X_encoded, y)
if mi < 0.01:
# 考虑用聚类简化
kmeans = KMeans(n_clusters=10)
X['category_cluster'] = kmeans.fit_predict(X_encoded)
3.3 特征交互作用检测
很多有价值的信号隐藏在特征交互中。我常用的检测方法是:
- 先用决策树生成交互特征
- 再用Permutation Importance评估交互强度
- 最后人工验证业务合理性
from sklearn.inspection import permutation_importance
tree = DecisionTreeClassifier(max_depth=5)
tree.fit(X, y)
# 生成交互特征
X['interaction'] = X['feature1'] * X['feature2']
# 评估重要性
result = permutation_importance(tree, X, y, n_repeats=10)
4. 典型问题排查手册
4.1 特征选择后效果反而变差
可能原因:
-
存在关键组合特征被单独剔除
- 解决方案:先用PCA生成组合特征
-
目标泄漏导致虚假相关性
- 解决方案:严格划分训练/验证集
-
非线性关系被忽略
- 解决方案:尝试基于树模型的方法
4.2 计算时间过长优化方案
对于超大规模特征集(>10万),我的优化策略:
- 先用Spark做分布式初筛
- 对剩余特征做分层抽样
- 使用基于GPU的XGBoost做最终选择
from pyspark.ml.feature import ChiSqSelector
selector = ChiSqSelector(numTopFeatures=1000)
model = selector.fit(spark_df)
4.3 类别不平衡时的特殊处理
当正负样本比例超过1:10时:
- 使用F1-score代替准确率作为评估指标
- 在RFE中使用stratified sampling
- 考虑使用SMOTE过采样
from imblearn.over_sampling import SMOTE
from sklearn.feature_selection import RFECV
smote = SMOTE()
X_res, y_res = smote.fit_resample(X, y)
selector = RFECV(estimator=LogisticRegression(),
scoring='f1',
cv=5)
5. 特征选择的高级应用场景
5.1 时间序列特征选择
在预测股价波动项目中,我开发了一套特殊方法:
- 先用tsfresh自动生成数百个时间特征
- 再用基于LSTM的Encoder-Decoder评估特征重要性
- 最后结合业务常识人工筛选
from tsfresh import extract_features
from tsfresh.select_features import select_features
extracted_features = extract_features(timeseries, column_id="id", column_sort="time")
features_filtered = select_features(extracted_features, y)
5.2 图像特征选择
处理CIFAR-10数据集时,我发现:
- 传统方法在像素级效果差
- 更好的做法是在CNN的中间层做选择
- 使用Grad-CAM可视化辅助决策
from tf_explain.core.grad_cam import GradCAM
explainer = GradCAM()
grid = explainer.explain((x_test, None), model, class_index=0)
5.3 文本特征选择
在新闻分类任务中,我的最佳实践是:
- 先用TF-IDF生成基础特征
- 再用LDA做主题建模
- 最后用Chi-square选择关键词
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
tfidf = TfidfVectorizer(max_features=10000)
X_tfidf = tfidf.fit_transform(texts)
lda = LatentDirichletAllocation(n_components=50)
X_lda = lda.fit_transform(X_tfidf)
在真实项目中,我通常会创建特征选择流水线,将多种方法组合使用。比如先用方差阈值快速过滤,再用RFE精细筛选,最后用特征重要性做交叉验证。这个过程往往需要迭代3-5次才能得到最优特征子集。记住,没有放之四海而皆准的方法,关键是要理解每种技术的适用场景和限制条件。
更多推荐
所有评论(0)