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"这样的高基数特征时,我的经验是:

  1. 先做目标编码(Target Encoding)
  2. 再计算该特征与目标的互信息
  3. 最后用聚类将相似类别合并
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 特征交互作用检测

很多有价值的信号隐藏在特征交互中。我常用的检测方法是:

  1. 先用决策树生成交互特征
  2. 再用Permutation Importance评估交互强度
  3. 最后人工验证业务合理性
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 特征选择后效果反而变差

可能原因:

  1. 存在关键组合特征被单独剔除
    • 解决方案:先用PCA生成组合特征
  2. 目标泄漏导致虚假相关性
    • 解决方案:严格划分训练/验证集
  3. 非线性关系被忽略
    • 解决方案:尝试基于树模型的方法

4.2 计算时间过长优化方案

对于超大规模特征集(>10万),我的优化策略:

  1. 先用Spark做分布式初筛
  2. 对剩余特征做分层抽样
  3. 使用基于GPU的XGBoost做最终选择
from pyspark.ml.feature import ChiSqSelector
selector = ChiSqSelector(numTopFeatures=1000)
model = selector.fit(spark_df)

4.3 类别不平衡时的特殊处理

当正负样本比例超过1:10时:

  1. 使用F1-score代替准确率作为评估指标
  2. 在RFE中使用stratified sampling
  3. 考虑使用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 时间序列特征选择

在预测股价波动项目中,我开发了一套特殊方法:

  1. 先用tsfresh自动生成数百个时间特征
  2. 再用基于LSTM的Encoder-Decoder评估特征重要性
  3. 最后结合业务常识人工筛选
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数据集时,我发现:

  1. 传统方法在像素级效果差
  2. 更好的做法是在CNN的中间层做选择
  3. 使用Grad-CAM可视化辅助决策
from tf_explain.core.grad_cam import GradCAM

explainer = GradCAM()
grid = explainer.explain((x_test, None), model, class_index=0)

5.3 文本特征选择

在新闻分类任务中,我的最佳实践是:

  1. 先用TF-IDF生成基础特征
  2. 再用LDA做主题建模
  3. 最后用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次才能得到最优特征子集。记住,没有放之四海而皆准的方法,关键是要理解每种技术的适用场景和限制条件。

更多推荐