自学内容网 自学内容网

机器学习中的支持向量机(SVM)

摘要:支持向量机(SVM)是一种监督学习算法,主要用于分类任务。其核心思想是通过寻找最优超平面来最大化不同类别间的间隔距离,其中靠近超平面的关键数据点称为支持向量。SVM通过核技巧处理非线性可分数据,常用核函数包括线性核、多项式核和径向基函数(RBF)核。Python实现中可使用scikit-learn库,需注意参数调优(如正则化参数C和核参数)对模型性能的影响。SVM优势在于高维数据处理能力强、内存效率高,但存在训练耗时、不适用于大规模数据及类别重叠场景的局限性。

目录

什么是支撑矢量机(SVM)

特别监测仪的工作原理

使用 Python 实现 SVM

SVM内核

线性核

多项式核

径向基函数(RBF)核

示例

SVM参数调优

示例

SVM分类器的优缺点

SVM分类器的优点

SVM分类器的缺点


什么是支撑矢量机(SVM)

支持向量机(SVM)是一种强大且灵活的监督机器学习算法,既可用于分类,也用于回归。但通常它们主要用于分类问题。SVM最早在20世纪60年代被引入,后来在1990年进行了完善。与其他机器学习算法相比,SVM有其独特的实现方式。如今,它们因能够处理多个连续和类别变量而极受欢迎。

特别监测仪的工作原理

SVM的目标是找到一个将数据点分为不同类别的超平面。超平面是二维空间中的一条直线、三维空间中的平面,或n维空间中的高维曲面。选择超平面的方式是为了最大化空间,即超平面与每个类别中最近数据点之间的距离。最近的数据点称为支撑向量。

超平面与数据点“x”之间的距离可以用公式 − 计算

distance = (w . x + b) / ||w|| 

其中“w”是权重向量,“b”是偏置项,“||w||”是权重向量的欧氏范数。权重向量“w”垂直于超平面,确定其方向,而偏置项“b”决定其位置。

最优超平面是通过求解一个优化问题来求得的,该问题是在所有数据点都正确分类的约束条件下最大化边际。换句话说,我们希望找到一个能最大化两类间距的超平面,同时确保没有数据点被错误分类。这是一个凸优化问题,可以通过二次规划求解。

如果数据点不可线性分离,我们可以使用一种称为核技巧的技术,将数据点映射到更高维空间,使其变得可分。核函数计算映射数据点之间的内积,而无需计算映射本身。这使得我们可以在高维空间中处理数据点,而无需支付映射的计算成本。

让我们通过以下图表详细理解它 −

SVM的工作原理

以下是SVM中的重要概念 −

  • 支持向量 − 最接近超平面的数据点称为支持向量。分隔线将借助这些数据点来定义。

  • 超平面 − 如上图所示,它是一个决策平面或空间,被一组具有不同类的对象分割。

  • 裕度 − 它可以定义为不同类别的近距离数据点两行之间的间隙。它可以计算为直线到支撑矢量之间的垂直距离。大边际被视为良好边际,小边际被视为坏边际。

使用 Python 实现 SVM

在 Python 中实现 SVM,我们将从以下标准库导入开始 −

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as sns; sns.set()

接下来,我们将从sklearn.dataset.sample_generator创建一个线性可分数据的样本数据集,用于使用SVM−进行分类。

from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples=100, centers=2, random_state=0, cluster_std=0.50)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='summer');

生成包含100个样本和2个簇的样本集后的输出如下 −

SVM 绘制数据点块

我们知道SVM支持判别分类。对于二维,它通过简单地将类别划分为一条线,在多维情况下选择流形。在上述数据集上实现方式如下 −

xfit = np.linspace(-1, 3.5)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='summer')
plt.plot([0.6], [2.1], 'x', color='black', markeredgewidth=4, markersize=12)
for m, b in [(1, 0.65), (0.5, 1.6), (-0.2, 2.9)]:
   plt.plot(xfit, m * xfit + b, '-k')
plt.xlim(-1, 3.5);   

输出如下 −

SVM绘图线/超平面

从上述输出中可以看到,有三种不同的分离器能够完美区分上述样本。

如前所述,SVM的主要目标是将数据集划分为多个类,以找到最大边际超平面(MMH),因此我们不再在类别之间画一条零线,而是在每条线周围画一个宽度的边距,直到最近的一点。具体步骤如下 −

xfit = np.linspace(-1, 3.5)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='summer')
for m, b, d in [(1, 0.65, 0.33), (0.5, 1.6, 0.55), (-0.2, 2.9, 0.2)]:
  yfit = m * xfit + b
  plt.plot(xfit, yfit, '-k')
  plt.fill_between(xfit, yfit - d, yfit + d, edgecolor='none',
        color='#AAAAAA', alpha=0.4)
  plt.xlim(-1, 3.5);

绘制最大边际超平面

从上述输出图中,我们可以轻松观察到判别分类器中的“边际”。SVM会选择最大化裕量的线。

接下来,我们将使用Scikit-Learn的支持向量分类器,基于这些数据训练SVM模型。这里,我们使用线性核来拟合SVM,如下 −

from sklearn.svm import SVC # "Support vector classifier"
model = SVC(kernel='linear', C=1E10)
model.fit(X, y)

输出如下 −

SVC(C=10000000000.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='linear', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False)

现在,为了更好地理解,下面将绘制二维SVC−的判定函数图。

def decision_function(model, ax=None, plot_support=True):
   if ax is None:
      ax = plt.gca()
   xlim = ax.get_xlim()
   ylim = ax.get_ylim()

为了评估模型,我们需要创建如下网格 −

x = np.linspace(xlim[0], xlim[1], 30)
y = np.linspace(ylim[0], ylim[1], 30)
Y, X = np.meshgrid(y, x)
xy = np.vstack([X.ravel(), Y.ravel()]).T
P = model.decision_function(xy).reshape(X.shape)

接下来,我们需要绘制决策边界和边际,如下 −

ax.contour(X, Y, P, colors='k',
   levels=[-1, 0, 1], alpha=0.5,
   linestyles=['--', '-', '--'])

现在,同样地绘制支撑向量如下 −

if plot_support:
   ax.scatter(model.support_vectors_[:, 0],
      model.support_vectors_[:, 1],
      s=300, linewidth=1, facecolors='none');
ax.set_xlim(xlim)
ax.set_ylim(ylim)

现在,利用该函数拟合我们的模型如下 −

plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='summer')
decision_function(model);

SVM最佳拟合超平面

从上述输出可以观察到,SVM分类器拟合到带有边距的数据,即虚线和支撑矢量,这些拟合的关键元素都与虚线相连。这些支持向量点存储在分类器的support_vectors_属性中,具体如下 −

model.support_vectors_

输出如下 −

array([[0.5323772 , 3.31338909],
   [2.11114739, 3.57660449],
   [1.46870582, 1.86947425]])

SVM内核

实际上,SVM算法通过核实现,将输入数据空间转换为所需形式。SVM使用一种称为核技巧的技术,核将一个低维输入空间转化为更高维空间。简单来说,核通过增加维度将不可分问题转换为可分问题。它使SVM更强大、更灵活且更准确。以下是SVM−所使用的一些核类型

线性核

它可以作为任意两个观测值之间的点积使用。线性核的公式如下 −

k(x,xi) = sum(x*xi)

从上述公式可以看出,两个向量的乘积是每对输入值相乘的和。

多项式核

它是更广义的线性核形式,区分了曲线输入空间和非线性输入空间。以下是多项式核−的公式

K(x, xi) = 1 + sum(x * xi)^d

这里 d 是多项式的次数,需要在学习算法中手动指定。

径向基函数(RBF)核

RBF核主要用于SVM分类,将输入空间映射到无限维空间中。按照公式在数学上解释 −

K(x,xi) = exp(-gamma * sum((x xi^2))

这里的伽马值范围从0到1。我们需要在学习算法中手动指定它。伽马的良好默认值是0.1。

我们为线性可分数据实现了SVM,也可以用Python实现非线性可分数据。这可以通过使用核来实现。

示例

以下是使用核创建SVM分类器的示例。我们将使用scikit-learn的虹膜数据集——

我们将从导入以下包开始 −

import pandas as pd
import numpy as np
from sklearn import svm, datasets
import matplotlib.pyplot as plt

现在,我们需要加载输入数据 −

iris = datasets.load_iris()

从该数据集中,我们取前两个特征如下 −

X = iris.data[:, :2]
y = iris.target

接下来,我们将用原始数据绘制出 SVM 边界,如下 −

x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
h = (x_max / x_min)/100
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
   np.arange(y_min, y_max, h))
X_plot = np.c_[xx.ravel(), yy.ravel()]

现在,我们需要给出正则化参数的值如下 −

C = 1.0

接下来,可以创建 SVM 分类器对象如下 −

Svc_classifier = svm.SVC(kernel='linear', C=C).fit(X, y)

Z = svc_classifier.predict(X_plot)
Z = Z.reshape(xx.shape)
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.contourf(xx, yy, Z, cmap=plt.cm.tab10, alpha=0.3)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(xx.min(), xx.max())
plt.title('Support Vector Classifier with linear kernel')

输出

Text(0.5, 1.0, 'Support Vector Classifier with linear kernel')

Curve

为了创建带有rbf核的SVM分类器,我们可以将核改为rbf,具体如下 −

Svc_classifier = svm.SVC(kernel='rbf', gamma ='auto',C=C).fit(X, y)
Z = svc_classifier.predict(X_plot)
Z = Z.reshape(xx.shape)
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.contourf(xx, yy, Z, cmap=plt.cm.tab10, alpha=0.3)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Set1)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(xx.min(), xx.max())
plt.title('Support Vector Classifier with rbf kernel')

输出

Text(0.5, 1.0, 'Support Vector Classifier with rbf kernel')

Classifier

我们把伽马值设为“自动”,但你也可以在0到1之间设置。

SVM参数调优

实际上,SVM通常需要调整参数以实现最佳性能。最重要的参数是核、正则化参数C和核特定的参数。

核参数决定了应使用的核类型。最常见的核类型包括线性核、多项式核、径向基函数(RBF)和S形核。线性核用于线性可分数据,而其他核用于非线性可分数据。

正则化参数C控制着最大化裕度与最小化分类误差之间的权衡。C值越高,分类器会以减少边缘为代价来最小化分类误差;C值越低,分类器即使误判更多,也会尽量最大化误差。

核特定的参数取决于所使用的核类型。例如,多项式核包含多项式次数和系数参数,而RBF核则有高斯函数宽度参数。

我们可以利用交叉验证来调整SVM的参数。交叉验证涉及将数据拆分为若干子集,并在每个子集上训练分类器,同时使用剩余子集进行测试。这使我们能够评估分类器在不同数据子集上的表现,并选择最佳参数集。

示例

# define the parameter grid
param_grid = {
   'C': [0.1, 1, 10, 100],
   'kernel': ['linear', 'poly', 'rbf', 'sigmoid'],
   'degree': [2, 3, 4],
   'coef0': [0.0, 0.1, 0.5],
   'gamma': ['scale', 'auto']
}

# create an SVM classifier
svm = SVC()

# perform grid search to find the best set of parameters
grid_search = GridSearchCV(svm, param_grid, cv=5)
grid_search.fit(X_train, y_train)
# print the best set of parameters and their accuracy
print("Best parameters:", grid_search.best_params_)
print("Best accuracy:", grid_search.best_score_)

我们首先从scikit-learn导入GridSearchCV模块,该工具用于对一组参数进行网格搜索。我们定义一个参数网格,包含每个参数的可能值。

我们用SVC()创建SVM分类器,然后连同参数网格和交叉验证折叠次数(cv=5)一起传递给GridSearchCV。然后调用 grid_search.fit(X_train, y_train) 进行网格搜索。

网格搜索完成后,我们分别用 grid_search.best_params_ 和 grid_search.best_score_ 打印最佳参数及其准确性。

输出

执行该程序时,你会得到以下输出 −

Best parameters: {'C': 0.1, 'coef0': 0.5, 'degree': 3, 'gamma': 'scale', 'kernel': 'poly'}
Best accuracy: 0.975

这意味着网格搜索找到的最佳参数集合为:C=0.1, coef0=0.5, degree=3, gamma=scale, and kernel=poly。这组参数在训练集上的准确率为97.5%。

你现在可以用这些参数创建新的SVM分类器,并在测试集上测试其性能。

SVM分类器的优缺点

SVM分类器的优点

SVM分类器具有极高的精度,并且在高维空间中表现良好。SVM分类器基本上使用训练点的子集,因此结果中对内存的消耗非常少。

SVM分类器的缺点

它们训练时间长,因此实际上不适合处理大型数据集。另一个缺点是SVM分类器在重叠类中表现不佳。


原文地址:https://blog.csdn.net/zl811103/article/details/156572805

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!