【机器学习与实战】分类与聚类算法:SVM支持向量机

123 阅读11分钟

【机器学习与实战】分类与聚类算法:SVM支持向量机

一、SVM概述
1、简介

支持向量机(Support Vector Machine,SVM)是一种有监督学习方法,主要用于分类和回归分析。它的基本思想是在特征空间中找到一个超平面,能够将不同类别的样本分开,并且使得离这个超平面最近的样本点到该平面的距离(即间隔)最大化。支持向量机在处理高维数据和非线性问题时表现良好。

SVM 能够执行线性或非线性分类、回归,甚至是异常值检测任务。它是机器学习领域最受欢迎的模型之一。SVM特别适用于中小型复杂数据集的分类。

1.jpeg

以下是支持向量机的一些关键概念:

(1)超平面(Hyperplane): 在一个 n 维空间中,一个 n-1 维的子空间就是一个超平面。在二维空间中,超平面就是一条直线;在三维空间中,超平面是一个平面。在支持向量机中,我们试图找到一个超平面,使得样本点能够被分成两个类别。

(2)支持向量(Support Vectors): 这些是离超平面最近的数据点,它们对于定义超平面并确定分类决策边界起着关键作用。支持向量机的训练过程中,只有支持向量的位置才会影响最终模型。

(3)间隔(Margin): 间隔是指超平面与支持向量之间的距离。支持向量机的目标是最大化这个间隔,从而提高模型的泛化能力。

(4)核函数(Kernel Function): 在处理非线性问题时,可以使用核函数将数据映射到更高维的空间中,使其在高维空间中线性可分。常用的核函数包括线性核、多项式核和径向基函数(RBF)核。

(5)C 参数: C 是一个正则化参数,它控制了对误分类样本的惩罚程度。较小的 C 值会导致更大的间隔,但可能允许一些样本被错误分类;较大的 C 值则会强调对误分类样本的惩罚,可能导致更复杂的决策边界。

2.png

当在一个平面上无法线性可分时,可以通过核函数将其映射到一个高维空间中,实现线性可分。

3.png

如何映射到高维空间,简单示例如下:

4.png

2、优点

(1)适用于高维空间: SVM在高维空间中表现出色,特别适用于处理具有许多特征的数据集,如文本分类或图像识别。

(2)泛化能力强: SVM通过最大化间隔的方式,有助于提高模型对新样本的泛化能力,降低过拟合的风险。

(3)对小样本数据效果好: 即使在样本量相对较小的情况下,SVM也能表现良好,这是因为它主要关注支持向量。

(4)核函数的灵活性: 使用核函数可以处理非线性问题,将数据映射到更高维的空间中,使其在高维空间中变得线性可分。

(5)对异常值的鲁棒性: SVM对于一些噪声和异常值的影响相对较小,支持向量主要受到那些距离超平面最近的样本的影响。

3、缺点

(1)计算开销较大: 对于大规模的数据集,SVM的训练和预测的计算开销较大,尤其在高维空间中。

(2)参数调优复杂: SVM有一些参数需要调优,例如C参数和核函数的选择,这可能需要通过交叉验证等方法来找到最优的参数设置。

(3)不适用于非线性大数据集: 在非线性大数据集上,训练和预测的速度可能会受到影响,且可能需要更长的时间。

(4)不适用于非平衡数据集: 对于类别不平衡的数据集,SVM可能会偏向于对多数类别进行优化,而忽略少数类别。

(5)不直接提供概率估计: SVM本身不直接提供类别的概率估计,而是通过一些启发式方法进行近似,这在某些应用中可能不够理想。(逻辑回归直接输出概率)

4、为什么SVM适合处理多维特征数据

(1)最大间隔分隔超平面: SVM的目标是找到一个最大间隔的分隔超平面,使得不同类别的样本在特征空间中的投影距离最远。在高维空间中,样本点相对于样本数量的维度较远,更容易找到一个超平面使得不同类别之间的距离最大化。

(2)高维度下线性可分性的增加: 随着特征维度的增加,数据在高维空间中更有可能变得线性可分。这是由于在高维空间中,不同类别的样本更容易在某个维度上有较大的差异,使得找到一个超平面来分隔它们变得更为可能。

(3)避免维度灾难: 在高维空间中,样本点之间的距离可能更加有意义。在低维空间中,由于维度较少,样本点之间的距离可能较小,这会导致模型更容易过拟合。而在高维空间中,样本点之间的距离相对较大,有助于避免维度灾难。

(4)支持向量的稀疏性: 在高维空间中,支持向量(决策边界附近的样本点)的数量相对较少,因为只有这些样本点对模型的构建起关键作用。这种稀疏性使得SVM在高维空间中更加高效。

(5)核技巧: SVM使用核函数将样本映射到高维空间,从而在低维空间中非线性可分的问题在高维空间中变得线性可分。这种核技巧在处理文本分类、图像识别等高维特征数据时尤为有效。

二、SVM算法定义
1、超平面最大间隔介绍

5.jpg

上左图显示了三种可能的线性分类器的决策边界:

虚线所代表的模型表现非常糟糕,甚至都无法正确实现分类。其余两个模型在这个训练集上表现堪称完美,但是它们的决策边界与实例过于接近,导致在面对新实例时,表现可能不会太好。

右图中的实线代表SVM分类器的决策边界,不仅分离了两个类别,且尽可能远离最近的训练实例。

2、硬间隔

在上面我们使用超平面进行分割数据的过程中,如果我们严格地让所有实例都不在最大间隔之间,并且位于正确的一边,这就是硬间隔分类。

硬间隔分类有两个问题

  • 首先,它只在数据是线性可分离的时候才有效
  • 其次,它对异常值非常敏感

比如,下图是有一个额外异常值的鸢尾花数据:

  • 左图的数据根本找不出硬间隔
  • 右图最终显示的决策边界与我们之前所看到的无异常值时的决策边界也大不相同,可能无法很好地泛化

6.jpg

3、软间隔

要避免这些问题,最好使用更灵活的模型。目标是尽可能在保持最大间隔宽阔和限制间隔违例(即位于最大间隔之上,甚至在错误的一边的实例)之间找到良好的平衡,这就是软间隔分类。

7.jpg

在 Scikit-Learn 的 SVM 类中,可以通过超参数 C 来控制这个平衡:C 值越小,则间隔越宽,但是间隔违例也会越多。

上图显示了在一个非线性可分离数据集上,两个软间隔 SVM 分类器各自的决策边界和间隔。

  • 左边使用了高 C 值,分类器的错误样本(间隔违例)较少,但是间隔也较小。
  • 右边使用了低C值,间隔大了很多,但是位于间隔上的实例也更多。

看起来第二个分类器的泛化效果更好,因为大多数间隔违例实际上都位于决策边界正确的一边,所以即便是在该训练集上,它做出的错误预测也会更少。

三、SKLearn中的应用
from sklearn import svm
X = [[0, 0], [1, 1]]
y = [0, 1]
clf = svm.SVC()
r = clf.fit(X, y)
pred = clf.predict([[2., 3.]])
print(pred)     # 预测值为 [1]
# 可以继续尝试 [[0,0]], [[-1, 0]], [[2, 2]]

上述过程大致如下图所示:

8.png

四、SVM损失函数

在SVM中,我们主要讨论三种损失函数:

9.jpg

  • 绿色:0/1损失

    • 当正例的点落在 y=0 这个超平面的下边,说明是分类正确,无论距离超平面所远多近,误差都是0。
    • 当这个正例的样本点落在 y=0 的上方的时候,说明分类错误,无论距离多远多近,误差都为1。
    • 图像就是上图绿色线。
  • 蓝色:SVM Hinge 损失函数

    • 损失函数的公式为:

      Loss=εi={1yi^,if yi10,if yi>1 \text{Loss} = \varepsilon_i = \begin{cases} 1 - \hat{y_i}, & \text{if } y_i \leqslant 1 \\ 0, & \text{if } y_i > 1 \end{cases}
    • 当一个正例的点落在 y=1 的直线上,此时和超平面距离为 1,也就是 1-ξ=1,那么误差 ξ=0;

    • 当它落在距离超平面 0.5 的地方,也就是 1-ξ=0.5,那么 ξ=0.5,也就是误差为0.5;

    • 当它落在 y=0 上的时候,此时和超平面距离为 0,也就是 1-ξ=0,那么误差为 ξ=1;

    • 当这个点落在了 y=0 的上方,被误分到了负例中,此时和超平面距离应该是负的,比如 -0.5,也就是 1-ξ=-0.5,那么误差 ξ=1.5。

    • 以此类推,画在二维坐标上就是上图中蓝色那根线了。

  • 红色:Logistic 损失函数

    • 损失函数的公式为:ln(1+eyi)ln(1+e^{-y_i})
    • yi=0y_i=0 时,损失等于 ln2,这样损失函数不是很漂亮,所以我们给这个损失函数除以 ln2,这样损失函数就是 ln(1+eyi)ln2\frac{ln(1+e^{-y_i})}{ln2}, 这样到 yi=0y_i=0 时,损失为 1,即损失函数过(0,1)点
    • 即上图中的红色线。
五、SVM实战应用
1、核函数简介

在现实任务中,原始样本空间内也许并不存在一个能正确划分两类样本的超平面。

对这样的问题,可将样本从原始空间映射到一个更高维的特征空间,使得样本在这个特征空间内线性可分。

10.png

(1)线性核:只能解决线性可分问题,简单易用,可解释性强。

(2)多项式核:依靠升维使得原本线性不可分的数据线性可分。可以解决某些非线性问题,幂数太大不适用。

(3)高斯核:也叫RBF核,或径向基核,函数可以映射到无限维(可用泰勒级数展开至无限维),只有一个参数。容易过拟合,可解释性差,计算速度比较慢。

(4)拉普拉斯核:拉普拉斯核彻底等价于指数核,惟一的区别在于前者对参数的敏感性下降,也是一种径向基核函数。

(5)Sigmoid核:也叫双曲正切核,采用Sigmoid函数作为核函数时,支持向量机实现的就是一种多层感知器神经网络。

注意:若核函数选择不合适,则意味着将样本映射到了一个不合适的特征空间,很可能导致性能不佳。

2、SVM内置对象
含义输入
svm.LinearSVC线性支持向量分类[penalty,loss,dual,tol,c,…]
svm.LinearSVR线性支持向量回归[epsilon,tol,C,loss,.]
svm.SVC非线性多维支持向量分类[C,kernel,degree,gamma,coef0,..]
svm.SVR非线性多维支持向量回归[kernel,degress,gamma,coef0,tol,..]
svm.NuSVCNu支持向量分类[nu,kernel,degree,gamma,.]
svm.NuSVRNu支持向量回归[nu,kernel,degress,gamma,..]
svm.OneClassSVM无监督异常值检测[kernel,degree,gamma,…]
3、心脏病患分类
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
heart = pd.read_csv('../regress/heart.csv')
x = heart.iloc[:, 0:13]
y = heart['target']
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
scaler = MinMaxScaler()
x_train = scaler.fit_transform(x_train)
x_test = scaler.transform(x_test)
# svm_model = SVC(kernel='linear', C=1.0)            # 线性核
# svm_model = SVC(kernel='rbf', C=1.0, gamma=1)        # 高斯核
svm_model = SVC(kernel='poly', C=1.0, degree=3)        # 多项式核
svm_model = SVC(kernel='sigmoid', C=1.0)            # Sigmoid核
# 训练模型
svm_model.fit(x_train, y_train)
# 预测
# y_pred = svm_model.predict(x_test)
score = svm_model.score(x_test, y_test)
print(score)
4、对鸢尾花进行多分类
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
x, y = load_iris(return_X_y=True)
print(x[1], y[1])
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=3)
scaler = StandardScaler()
scaler.fit_transform(x_train)
scaler.transform(x_test)
svm_model = SVC(kernel='rbf', C=1.0, gamma=1)
svm_model.fit(x_train, y_train)
# 预测
y_pred = svm_model.predict(x_test)
print(y_pred)
score = svm_model.score(x_test, y_test)
print(score)