在机器学习领域,降维是一种常见的预处理技术,它可以帮助减少数据的复杂性,提高模型的泛化能力。本文将介绍如何使用主成分分析(PCA)和非负矩阵分解(NMF)进行降维,并结合支持向量分类器(SVC)进行预测。此外,还将展示如何利用GridSearchCV和Pipeline来优化模型参数,以提高分类的准确性。
首先,需要准备数据集。在这个例子中,使用的是手写数字识别数据集,该数据集包含了1797个样本,每个样本有64个特征。目标是将这些高维数据降维到较低的维度,然后使用支持向量分类器进行分类。
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA, NMF
from sklearn.feature_selection import SelectKBest, mutual_info_classif
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import MinMaxScaler
from sklearn.svm import LinearSVC
# 加载数据集
X, y = load_digits(return_X_y=True)
接下来,构建一个Pipeline,它包括数据预处理、降维和分类三个步骤。在降维步骤中,可以通过参数网格搜索(GridSearchCV)来比较不同的降维方法,如PCA、NMF和单变量特征选择。
pipe = Pipeline([
("scaling", MinMaxScaler()),
("reduce_dim", "passthrough"),
("classify", LinearSVC(dual=False, max_iter=10000)),
])
在参数网格搜索中,定义了不同的参数组合,包括不同的降维方法、降维后的特征数量以及分类器的正则化参数C。通过这种方式,可以在单次交叉验证运行中比较不同类别的估计器。
N_FEATURES_OPTIONS = [2, 4, 8]
C_OPTIONS = [1, 10, 100, 1000]
param_grid = [
{
{ "reduce_dim": [PCA(iterated_power=7), NMF(max_iter=1000)]}
"reduce_dim__n_components": N_FEATURES_OPTIONS,
"classify__C": C_OPTIONS,
},
{
{ "reduce_dim": [SelectKBest(mutual_info_classif)]}
"reduce_dim__k": N_FEATURES_OPTIONS,
"classify__C": C_OPTIONS,
},
]
在定义好Pipeline和参数网格后,可以使用GridSearchCV来训练模型并评估不同参数组合的性能。GridSearchCV会自动进行交叉验证,并返回最佳的参数组合和对应的模型。
grid = GridSearchCV(pipe, n_jobs=1, param_grid=param_grid)
grid.fit(X, y)
通过比较不同降维方法的性能,可以发现PCA在本例中表现最佳,将数据降维到8个特征时,分类准确率达到了最高。此外,还可以通过绘制不同降维方法的性能对比图来直观地展示结果。
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
mean_scores = np.array(grid.cv_results_["mean_test_score"])
mean_scores = mean_scores.reshape(len(C_OPTIONS), -1, len(N_FEATURES_OPTIONS)).max(axis=0)
mean_scores = pd.DataFrame(mean_scores.T, index=N_FEATURES_OPTIONS, columns=["PCA", "NMF", "KBest(mutual_info_classif)"])
ax = mean_scores.plot.bar()
ax.set_title("比较特征降维技术")
ax.set_xlabel("降维后的特征数量")
ax.set_ylabel("数字分类准确率")
ax.set_ylim((0, 1))
ax.legend(loc="upper left")
plt.show()
在Pipeline中使用GridSearchCV时,有时值得存储特定转换器的状态,因为它可能会被再次使用。因此,使用memory参数来启用缓存。需要注意的是,当转换器的拟合成本较高时,使用memory参数启用缓存才有意义。
from sklearn.externals import joblib
from sklearn.pipeline import Pipeline
from sklearn.decomposition import PCA
from sklearn.svm import LinearSVC
memory = joblib.Memory(cachedir="cachedir", verbose=10)
cached_pipe = Pipeline([
("reduce_dim", PCA()),
("classify", LinearSVC(dual=False, max_iter=10000))
], memory=memory)
# 使用缓存的Pipeline进行网格搜索
memory.clear(warn=False)
通过使用缓存,可以在后续的参数配置中避免重复拟合PCA,从而节省处理时间。因此,当拟合转换器的成本较高时,使用memory参数缓存Pipeline是非常有益的。