在机器学习领域,特征选择是一个重要的步骤,它可以帮助从大量特征中挑选出对模型预测能力有显著影响的特征。本文将展示如何通过单变量特征选择方法来提高含噪声数据集上的分类准确性,并使用支持向量机(SVM)模型进行分类前后的比较分析。
首先,需要生成一些样本数据。在这个例子中,将使用著名的鸢尾花(iris)数据集,并人为添加一些噪声特征,以模拟真实世界中的数据情况。
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# 加载鸢尾花数据集
X, y = load_iris(return_X_y=True)
# 生成一些与目标变量无关的噪声数据
E = np.random.RandomState(42).uniform(0, 0.1, size=(X.shape[0], 20))
# 将噪声数据添加到原始特征中
X = np.hstack((X, E))
# 划分数据集,用于特征选择和分类器评估
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
接下来,将使用单变量特征选择方法,通过F检验来评估特征的重要性,并选择出最显著的四个特征。
from sklearn.feature_selection import SelectKBest, f_classif
# 使用SelectKBest选择最重要的四个特征
selector = SelectKBest(f_classif, k=4)
selector.fit(X_train, y_train)
# 计算特征的单变量得分,并进行归一化处理
scores = -np.log10(selector.pvalues_)
scores /= scores.max()
import matplotlib.pyplot as plt
# 绘制特征的单变量得分
X_indices = np.arange(X.shape[-1])
plt.figure(1)
plt.clf()
plt.bar(X_indices - 0.05, scores, width=0.2)
plt.title("特征单变量得分")
plt.xlabel("特征编号")
plt.ylabel(r"单变量得分 ($-Log(p_{value})$)")
plt.show()
从图中可以看出,在所有特征中,只有原始的四个特征是显著的,它们具有最高的单变量得分。
将比较在应用单变量特征选择前后,SVM分类器的分类准确性和模型权重的变化。
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import MinMaxScaler
from sklearn.svm import LinearSVC
# 不进行特征选择的SVM分类器
clf = make_pipeline(MinMaxScaler(), LinearSVC())
clf.fit(X_train, y_train)
print("不进行特征选择的分类准确性: {:.3f}".format(clf.score(X_test, y_test)))
# 计算SVM权重
svm_weights = np.abs(clf[-1].coef_).sum(axis=0)
svm_weights /= svm_weights.sum()
# 进行特征选择的SVM分类器
clf_selected = make_pipeline(SelectKBest(f_classif, k=4), MinMaxScaler(), LinearSVC())
clf_selected.fit(X_train, y_train)
print("进行特征选择后的分类准确性: {:.3f}".format(clf_selected.score(X_test, y_test)))
# 计算选择后SVM的权重
svm_weights_selected = np.abs(clf_selected[-1].coef_).sum(axis=0)
svm_weights_selected /= svm_weights_selected.sum()
# 绘制特征选择前后的SVM权重比较图
plt.bar(X_indices - 0.45, scores, width=0.2, label=r"单变量得分 ($-Log(p_{value})$)")
plt.bar(X_indices - 0.25, svm_weights, width=0.2, label="SVM权重")
plt.bar(X_indices[selector.get_support()] - 0.05, svm_weights_selected, width=0.2, label="选择后的SVM权重")
plt.title("特征选择比较")
plt.xlabel("特征编号")
plt.yticks(())
plt.axis("tight")
plt.legend(loc="upper right")
plt.show()
通过比较,可以看到,在不进行特征选择的情况下,SVM模型虽然赋予了前四个原始显著特征较大的权重,但也选择了很多非信息性特征。而在应用单变量特征选择之后,SVM模型对显著特征的权重有所增加,从而提高了分类的准确性。