RBF内核的显式特征图近似

一个示例,说明了RBF内核的特征图的近似值。

它显示了如何使用RBFSampler和Nystroem来近似RBF内核的特征图,以便在数字数据集上使用SVM进行分类。比较了使用原始空间中的线性SVM,使用近似映射的线性SVM和使用内核化SVM的结果。显示了不同数量的蒙特卡洛采样的时间和精度(在RBFSampler的情况下,它使用随机傅里叶特征)和训练集的不同大小的子集(对于Nystroem)用于近似映射。

请注意,这里的数据集不足以显示核近似的好处,因为精确的SVM仍然相当快。

对更多维度进行采样显然会带来更好的分类结果,但代价更高。这意味着在运行时间和精度之间需要权衡,这由参数n_components给出。请注意,通过sklearn.linear_model.SGDClassifier使用随机梯度下降可大大加快求解线性SVM以及近似内核SVM的速度。对于内核化SVM,这是不容易实现的。

Python包和数据集导入,加载数据集

# 作者: Gael Varoquaux <gael dot varoquaux at normalesup dot org>
#       Andreas Mueller <amueller@ais.uni-bonn.de>
# 执照: BSD 3 clause

print(__doc__)

# 标准的、科学的Python包导入过程
import matplotlib.pyplot as plt
import numpy as np
from time import time

# 导入数据集,分类器和性能指标
from sklearn import datasets, svm, pipeline
from sklearn.kernel_approximation import (RBFSampler,
                                          Nystroem)
from sklearn.decomposition import PCA

# 手写数字数据集
digits = datasets.load_digits(n_class=9)

时序图和精度图

要将分类器应用于此数据,我们需要将图像展平,以将数据转换为(样本,特征)矩阵:

n_samples = len(digits.data)
data = digits.data / 16.
data -= data.mean(axis=0)

# 对手写数字数据集的前半段进行学习
data_train, targets_train = (data[:n_samples // 2],
                             digits.target[:n_samples // 2])


# 预测手写数字数据集的后半段
data_test, targets_test = (data[n_samples // 2:],
                           digits.target[n_samples // 2:])
# data_test = scaler.transform(data_test)

# 创造分类器:一个支持向量机
kernel_svm = svm.SVC(gamma=.2)
linear_svm = svm.LinearSVC()

# 用核估计方式创建管道
# 和线性svm
feature_map_fourier = RBFSampler(gamma=.2, random_state=1)
feature_map_nystroem = Nystroem(gamma=.2, random_state=1)
fourier_approx_svm = pipeline.Pipeline([("feature_map", feature_map_fourier),
                                        ("svm", svm.LinearSVC())])

nystroem_approx_svm = pipeline.Pipeline([("feature_map", feature_map_nystroem),
                                        ("svm", svm.LinearSVC())])

# 用线性及带核的支持向量机进行拟合和预测:

kernel_svm_time = time()
kernel_svm.fit(data_train, targets_train)
kernel_svm_score = kernel_svm.score(data_test, targets_test)
kernel_svm_time = time() - kernel_svm_time

linear_svm_time = time()
linear_svm.fit(data_train, targets_train)
linear_svm_score = linear_svm.score(data_test, targets_test)
linear_svm_time = time() - linear_svm_time

sample_sizes = 30 * np.arange(110)
fourier_scores = []
nystroem_scores = []
fourier_times = []
nystroem_times = []

for D in sample_sizes:
    fourier_approx_svm.set_params(feature_map__n_components=D)
    nystroem_approx_svm.set_params(feature_map__n_components=D)
    start = time()
    nystroem_approx_svm.fit(data_train, targets_train)
    nystroem_times.append(time() - start)

    start = time()
    fourier_approx_svm.fit(data_train, targets_train)
    fourier_times.append(time() - start)

    fourier_score = fourier_approx_svm.score(data_test, targets_test)
    nystroem_score = nystroem_approx_svm.score(data_test, targets_test)
    nystroem_scores.append(nystroem_score)
    fourier_scores.append(fourier_score)

# 绘制结果:
plt.figure(figsize=(164))
accuracy = plt.subplot(121)
# 设置次坐标轴,显示时间
timescale = plt.subplot(122)

accuracy.plot(sample_sizes, nystroem_scores, label="Nystroem approx. kernel")
timescale.plot(sample_sizes, nystroem_times, '--',
               label='Nystroem approx. kernel')

accuracy.plot(sample_sizes, fourier_scores, label="Fourier approx. kernel")
timescale.plot(sample_sizes, fourier_times, '--',
               label='Fourier approx. kernel')

# 绘制rbf和线性核的横线
accuracy.plot([sample_sizes[0], sample_sizes[-1]],
              [linear_svm_score, linear_svm_score], label="linear svm")
timescale.plot([sample_sizes[0], sample_sizes[-1]],
               [linear_svm_time, linear_svm_time], '--', label='linear svm')

accuracy.plot([sample_sizes[0], sample_sizes[-1]],
              [kernel_svm_score, kernel_svm_score], label="rbf svm")
timescale.plot([sample_sizes[0], sample_sizes[-1]],
               [kernel_svm_time, kernel_svm_time], '--', label='rbf svm')

# 为数据集的维度设置竖线
accuracy.plot([6464], [0.71], label="n_features")

# 图例和标题
accuracy.set_title("Classification accuracy")
timescale.set_title("Training times")
accuracy.set_xlim(sample_sizes[0], sample_sizes[-1])
accuracy.set_xticks(())
accuracy.set_ylim(np.min(fourier_scores), 1)
timescale.set_xlabel("Sampling steps = transformed feature dimension")
accuracy.set_ylabel("Classification accuracy")
timescale.set_ylabel("Training time in seconds")
accuracy.legend(loc='best')
timescale.legend(loc='best')
plt.tight_layout()
plt.show()

输出:

RBF内核SVM和线性SVM的决策平面

第二个图显示了带有近似内核图的RBF内核SVM和线性SVM的决策平面。该图显示了投影到数据的前两个主要成分上的分类器的决策面。 这种可视化应该不费吹灰之力就能完成,因为它只是决策面上64个维度中的一个有趣切片。 特别要注意的是,数据点(用点表示)不一定要分类到它所在的区域,因为它不会位于前两个主要成分所跨越的平面上。 内核近似中详细介绍了RBFSampler和Nystroem的用法。

# 可视化决策平面,向下投影到数据集的前两个主要组成部分
pca = PCA(n_components=8).fit(data_train)

X = pca.transform(data_train)

# 沿着前两个主要成分生成网格
multiples = np.arange(-220.1)
# 沿第一成分走
first = multiples[:, np.newaxis] * pca.components_[0, :]
# 沿第二成分走
second = multiples[:, np.newaxis] * pca.components_[1, :]
# 结合起来
grid = first[np.newaxis, :, :] + second[:, np.newaxis, :]
flat_grid = grid.reshape(-1, data.shape[1])

# 为图像设置标题
titles = ['SVC with rbf kernel',
          'SVC (linear kernel)\n with Fourier rbf feature map\n'
          'n_components=100',
          'SVC (linear kernel)\n with Nystroem rbf feature map\n'
          'n_components=100']

plt.figure(figsize=(187.5))
plt.rcParams.update({'font.size'14})

# 预测并绘图
for i, clf in enumerate((kernel_svm, nystroem_approx_svm,
                         fourier_approx_svm)):
    # 绘制决策边界
    # 为此,我们将为网格[x_min,x_max] x [y_min,y_max]中的每个点分配颜色
    plt.subplot(13, i + 1)
    Z = clf.predict(flat_grid)

    # 将结果放入彩色的绘图
    Z = Z.reshape(grid.shape[:-1])
    plt.contourf(multiples, multiples, Z, cmap=plt.cm.Paired)
    plt.axis('off')

    # 同时,绘制训练数据点
    plt.scatter(X[:, 0], X[:, 1], c=targets_train, cmap=plt.cm.Paired,
                edgecolors=(000))

    plt.title(titles[i])
plt.tight_layout()
plt.show()

输出:

脚本的总运行时间:(0分钟2.195秒)