1. 项目概述
在机器学习领域,模型选择和特征工程是决定项目成败的两个关键因素。这次我使用经典的UCI机器学习数据集,系统性地比较了KNN、SVM和随机森林三种常见分类算法的表现,并深入探讨了不同特征选择方法对模型性能的影响。这个实验不仅验证了不同算法在相同数据集上的表现差异,更重要的是揭示了特征选择与模型性能之间的微妙关系。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 实验设计与数据准备
2.1 UCI数据集选择与预处理
我选择了UCI机器学习库中的乳腺癌威斯康星州诊断数据集作为实验对象。这个数据集包含569个样本,每个样本有30个特征,目标变量是良性和恶性两类。选择这个数据集主要基于三个考虑:首先,它规模适中,适合快速迭代实验;其次,特征维度较高,适合展示特征选择的效果;最后,这是一个经典的二分类问题,结果易于解释。
数据预处理包括以下几个关键步骤:
- 缺失值处理:检查数据集后发现没有缺失值,省去了填充步骤
- 特征标准化:使用StandardScaler对所有特征进行标准化处理
- 数据集划分:按照7:3的比例划分训练集和测试集
- 随机种子固定:设置random_state=42确保实验可复现
注意:虽然这个数据集已经相对干净,但标准化步骤对KNN和SVM这类基于距离的算法至关重要。随机森林虽然对特征尺度不敏感,但为了公平比较,我们对所有模型使用相同的预处理数据。
2.2 模型选择与参数设置
本次实验选择了三种具有代表性的分类算法:
-
K近邻(KNN):
- 基础参数:n_neighbors=5, weights='uniform'
- 调参范围:n_neighbors从3到15,考虑距离加权
-
支持向量机(SVM):
- 基础参数:C=1.0, kernel='rbf'
- 调参范围:C值在0.1到10之间,尝试线性核和RBF核
-
随机森林(RF):
- 基础参数:n_estimators=100, max_depth=None
- 调参范围:n_estimators从50到200,max_depth从3到10
3. 特征选择方法实现
3.1 基于统计的特征筛选
首先采用方差分析和卡方检验这两种经典的统计方法进行特征初筛:
python复制from sklearn.feature_selection import SelectKBest, f_classif, chi2
# 方差分析选择
selector_anova = SelectKBest(f_classif, k=10)
X_anova = selector_anova.fit_transform(X, y)
# 卡方检验选择
selector_chi2 = SelectKBest(chi2, k=10)
X_chi2 = selector_chi2.fit_transform(X, y)
这两种方法计算速度快,适合作为特征选择的基线方法。实际测试发现,两种方法选出的特征有约70%的重叠,说明数据中存在一些统计显著性很强的特征。
3.2 基于模型的特征重要性
随机森林自带特征重要性评估功能,我们训练基础随机森林模型后,可以提取特征重要性:
python复制from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
importances = rf.feature_importances_
将重要性排序后,我们选择前10个特征作为筛选结果。与统计方法相比,基于模型的方法考虑了特征间的交互作用,通常能发现更有意义的特征组合。
3.3 SHAP值特征分析
SHAP(SHapley Additive exPlanations)是近年来流行的特征解释方法,它基于博弈论,可以更公平地评估每个特征的贡献:
python复制import shap
explainer = shap.TreeExplainer(rf)
shap_values = explainer.shap_values(X_train)
shap.summary_plot(shap_values, X_train)
SHAP分析不仅能给出特征重要性排序,还能显示每个特征对预测方向的影响(正向或负向),这对理解模型行为非常有帮助。在我们的实验中,SHAP揭示了一些统计方法未能发现的非线性特征关系。
4. 模型训练与性能比较
4.1 基础模型性能对比
在完整特征集上,三种模型的基线表现如下(测试集准确率):
| 模型 | 准确率 | 训练时间(s) | 预测时间(ms/sample) |
|---|---|---|---|
| KNN | 0.947 | 0.001 | 0.45 |
| SVM | 0.965 | 0.032 | 0.12 |
| RF | 0.959 | 0.215 | 0.08 |
从表中可以看出,SVM在这个数据集上表现最好,但差异不大。KNN虽然简单,但表现不俗,而随机森林在训练时间上明显更长。
4.2 特征选择后的性能变化
使用不同特征选择方法后,模型性能变化很有趣:
-
统计方法筛选特征:
- KNN准确率提升到0.953
- SVM准确率保持在0.965
- RF准确率略降至0.953
-
基于模型的重要性筛选:
- KNN准确率0.959
- SVM准确率0.965
- RF准确率0.965
-
SHAP值筛选:
- KNN准确率0.959
- SVM准确率0.971
- RF准确率0.965
关键发现:特征选择并不总是提高准确率,但能显著提升模型效率。特别是对KNN,特征维度减少后预测速度提高了3倍。SVM在使用SHAP筛选的特征后表现最好,说明特征选择方法需要与模型特性匹配。
5. 深入分析与实践建议
5.1 为什么特征选择效果因模型而异?
这个现象可以从算法原理角度解释:
- KNN受益于去除无关特征,因为距离计算对噪声敏感
- SVM本身有较强的特征选择能力,特别是使用L1正则化时
- 随机森林自带特征选择机制,外部筛选可能干扰其内在特征交互
5.2 特征选择实践建议
基于这次实验,我总结出以下实用建议:
- 对于中小型数据集,SHAP分析值得投入,它能提供传统方法无法获得的洞察
- KNN这类简单模型从特征选择中获益最大,应该优先考虑
- 不要盲目追求最高准确率,要权衡计算效率和维护成本
- 特征选择方法应该与最终使用的模型协调,不一致可能导致次优结果
5.3 常见问题与解决方案
在实际操作中,我遇到了几个典型问题:
-
问题:SHAP计算速度慢
解决:对大型数据集,可以采样计算或使用KernelExplainer替代TreeExplainer -
问题:特征选择后模型不稳定
解决:检查特征间的相关性,高度相关的特征应该合并或去除 -
问题:不同特征选择方法结果差异大
解决:这通常意味着数据中没有明显的主导特征,需要更深入的特征工程
6. 扩展实验与进阶方向
为了更全面评估特征选择的效果,我进一步做了以下实验:
-
递归特征消除(RFE):
使用SVM作为基模型,逐步去除最不重要的特征
结果与一次性选择相似,但计算成本更高 -
嵌入式方法:
尝试了Lasso和弹性网络,发现对线性模型效果更好 -
特征转换:
测试了PCA和非负矩阵分解,虽然降低了维度,但牺牲了可解释性
对于想深入研究的读者,我建议探索以下方向:
- 深度学习中的自动特征提取
- 针对特定领域知识的定制化特征工程
- 特征选择与超参数优化的联合调参
