在机器学习中,数据的质量直接影响模型的性能。当数据集中包含噪声或非信息性特征时,模型的分类精度往往会受到影响。本文以鸢尾花数据集为例,展示了如何通过添加噪声特征并应用单变量特征选择来提高支持向量机(SVM)的分类精度。
首先,使用Python的NumPy库生成一些与原始特征不相关的噪声数据,并将其添加到鸢尾花数据集中。然后,将数据集分为训练集和测试集,以便后续的特征选择和模型评估。
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-test进行单变量特征选择,以选择四个最重要的特征。通过计算每个特征的p值,并将其转换为对数尺度上的分数,可以评估每个特征的重要性。
from sklearn.feature_selection import SelectKBest, f_classif
import matplotlib.pyplot as plt
# 使用F-test进行单变量特征选择
selector = SelectKBest(f_classif, k=4)
selector.fit(X_train, y_train)
scores = -np.log10(selector.pvalues_)
scores /= scores.max()
# 绘制特征的单变量分数
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模型的分类精度和权重的变化。首先,训练一个没有进行特征选择的SVM模型,并计算其在测试集上的分类精度。然后,使用单变量特征选择后的特征来训练另一个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()
# 绘制特征选择的比较
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之前应用单变量特征选择可以增加SVM赋予显著特征的权重,从而提高分类精度。