📜  机器学习-支持向量机(SVM)

📅  最后修改于: 2020-09-27 09:12:32             🧑  作者: Mango

支持向量机算法

支持向量机(SVM)是最流行的监督学习算法之一,可用于分类以及回归问题。但是,首先,它用于机器学习中的分类问题。

SVM算法的目标是创建可以将n维空间划分为类的最佳直线或决策边界,以便我们将来可以轻松地将新数据点放在正确的类别中。最佳决策边界称为超平面。

SVM选择有助于创建超平面的极限点/向量。这些极端情况称为支持向量,因此算法称为支持向量机。考虑下图,其中使用决策边界或超平面将两个不同的类别分类:

示例:可以通过我们在KNN分类器中使用的示例来理解SVM。假设我们看到一只奇怪的猫,它也具有狗的某些特征,因此如果我们想要一个可以准确识别它是猫还是狗的模型,那么可以使用SVM算法来创建这样的模型。我们将首先用大量的猫和狗的图像训练模型,以便它可以了解猫和狗的不同特征,然后我们用这个奇怪的生物对其进行测试。因此,当支持向量在这两个数据(猫和狗)之间创建决策边界并选择极端情况(支持向量)时,它将看到猫和狗的极端情况。根据支持向量,它将分类为猫。考虑下图:

SVM算法可用于人脸检测,图像分类,文本分类等。

SVM的类型

SVM可以有两种类型:

  • 线性SVM:线性SVM用于线性可分离数据,这意味着如果可以使用一条直线将数据集分为两类,则将此类数据称为线性可分离数据,并且将分类器称为线性SVM分类器。
  • 非线性SVM:非线性SVM用于非线性分离的数据,这意味着如果无法使用直线对数据集进行分类,则将此类数据称为非线性数据,并将使用的分类器称为“非线性”线性SVM分类器。

SVM算法中的超平面和支持向量:

超平面:可以有多条线/决策边界来分离n维空间中的类,但是我们需要找出有助于对数据点进行分类的最佳决策边界。最佳边界称为SVM的超平面。

超平面的尺寸取决于数据集中存在的特征,这意味着如果有2个特征(如图所示),则超平面将是一条直线。并且如果有3个要素,则超平面将是2维平面。

我们总是创建一个具有最大余量的超平面,这意味着数据点之间的最大距离。

支持向量:

最接近超平面并影响超平面位置的数据点或向量称为支持向量。由于这些向量支持超平面,因此称为支持向量。

SVM如何工作?

线性SVM:

通过示例可以了解SVM算法的工作原理。假设我们有一个具有两个标签(绿色和蓝色)的数据集,并且该数据集具有两个特征x1和x2。我们想要一个可以将坐标对(x1,x2)分类为绿色或蓝色的分类器。考虑下图:

由于它是二维空间,因此只需使用一条直线,我们就可以轻松地将这两个类分开。但是可以有多行可以将这些类分开。考虑下图:

因此,SVM算法有助于找到最佳的直线或决策边界。最好的边界或区域称为超平面。 SVM算法从两个类中找到线的最接近点。这些点称为支持向量。向量与超平面之间的距离称为余量。 SVM的目标是最大化此余量。具有最大余量的超平面称为最佳超平面。

非线性SVM:

如果数据是线性排列的,那么我们可以使用一条直线将其分开,但是对于非线性数据,我们无法绘制一条直线。考虑下图:

因此,要分离这些数据点,我们需要再增加一个维度。对于线性数据,我们使用了两个维度x和y,因此对于非线性数据,我们将添加第三个维度z。可以计算为:

通过添加第三维,样本空间将变为下图所示:

因此,现在,SVM将以以下方式将数据集划分为类。考虑下图:

由于我们处于3维空间,因此它看起来像是一个平行于x轴的平面。如果我们在z = 1的二维空间中对其进行转换,则它将变为:

因此,在非线性数据的情况下,我们得到半径为1的圆周。

支持向量机的Python实现

现在,我们将使用Python实现SVM算法。在这里,我们将使用在Logistic回归和KNN分类中使用的相同数据集user_data。

  • 数据预处理步骤

在数据预处理步骤之前,代码将保持不变。下面是代码:

#Data Pre-processing Step
# importing libraries
import numpy as nm
import matplotlib.pyplot as mtp
import pandas as pd

#importing datasets
data_set= pd.read_csv('user_data.csv')

#Extracting Independent and dependent Variable
x= data_set.iloc[:, [2,3]].values
y= data_set.iloc[:, 4].values

# Splitting the dataset into training and test set.
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test= train_test_split(x, y, test_size= 0.25, random_state=0)
#feature Scaling
from sklearn.preprocessing import StandardScaler  
st_x= StandardScaler()  
x_train= st_x.fit_transform(x_train)  
x_test= st_x.transform(x_test)     

执行完上述代码后,我们将对数据进行预处理。该代码将给数据集如下:

测试集的缩放输出将是:

使SVM分类器适合训练集:

现在,训练集将适合SVM分类器。要创建SVM分类器,我们将从Sklearn.svm库中导入SVC类。下面是它的代码:

from sklearn.svm import SVC# "Support vector classifier"
classifier = SVC(kernel='linear', random_state=0)
classifier.fit(x_train, y_train)

在上面的代码中,我们使用了kernel =’linear’,因为在这里我们正在为线性可分离的数据创建SVM。但是,我们可以将其更改为非线性数据。然后我们将分类器拟合到训练数据集(x_train,y_train)

输出:

Out[8]: 
SVC(C=1.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=0,
    shrinking=True, tol=0.001, verbose=False)

可以通过更改C(正则化因子),γ和内核的值来更改模型性能。

  • 预测测试结果:
    现在,我们将预测测试集的输出。为此,我们将创建一个新的向量y_pred。下面是它的代码:
#Predicting the test set result
y_pred= classifier.predict(x_test)

得到y_pred向量后,我们可以比较y_pred和y_test的结果,以检查实际值和预测值之间的差异。

输出:以下是测试集预测的输出:

  • 创建混淆矩阵:
    现在,我们将看到与Logistic回归分类器相比,SVM分类器的性能是多少个错误的预测。要创建混淆矩阵,我们需要导入sklearn库的confusion_matrix 函数 。导入函数,我们将使用新变量cm调用它。该函数有两个参数,主要是y_true (实际值)和y_pred (分类器返回的目标值)。下面是它的代码:
#Creating the Confusion matrix
from sklearn.metrics import confusion_matrix
cm= confusion_matrix(y_test, y_pred)

输出:

从上面的输出图像中可以看到,有66 + 24 = 90个正确的预测,而8 + 2 = 10个正确的预测。因此,可以说,与Logistic回归模型相比,我们的SVM模型得到了改进。

  • 可视化训练集结果:
    现在我们将训练集结果可视化,下面是它的代码:
from matplotlib.colors import ListedColormap
x_set, y_set = x_train, y_train
x1, x2 = nm.meshgrid(nm.arange(start = x_set[:, 0].min() - 1, stop = x_set[:, 0].max() + 1, step  =0.01),
nm.arange(start = x_set[:, 1].min() - 1, stop = x_set[:, 1].max() + 1, step = 0.01))
mtp.contourf(x1, x2, classifier.predict(nm.array([x1.ravel(), x2.ravel()]).T).reshape(x1.shape),
alpha = 0.75, cmap = ListedColormap(('red', 'green')))
mtp.xlim(x1.min(), x1.max())
mtp.ylim(x2.min(), x2.max())
for i, j in enumerate(nm.unique(y_set)):
    mtp.scatter(x_set[y_set == j, 0], x_set[y_set == j, 1],
        c = ListedColormap(('red', 'green'))(i), label = j)
mtp.title('SVM classifier (Training set)')
mtp.xlabel('Age')
mtp.ylabel('Estimated Salary')
mtp.legend()
mtp.show()

输出:

通过执行以上代码,我们将获得以下输出:

如我们所见,以上输出看起来与Logistic回归输出类似。在输出中,由于在分类器中使用了线性核,因此我们将直线作为超平面。上面我们还讨论了,对于2d空间,SVM中的超平面是一条直线。

  • 可视化测试集结果:
#Visulaizing the test set result
from matplotlib.colors import ListedColormap
x_set, y_set = x_test, y_test
x1, x2 = nm.meshgrid(nm.arange(start = x_set[:, 0].min() - 1, stop = x_set[:, 0].max() + 1, step  =0.01),
nm.arange(start = x_set[:, 1].min() - 1, stop = x_set[:, 1].max() + 1, step = 0.01))
mtp.contourf(x1, x2, classifier.predict(nm.array([x1.ravel(), x2.ravel()]).T).reshape(x1.shape),
alpha = 0.75, cmap = ListedColormap(('red','green' )))
mtp.xlim(x1.min(), x1.max())
mtp.ylim(x2.min(), x2.max())
for i, j in enumerate(nm.unique(y_set)):
    mtp.scatter(x_set[y_set == j, 0], x_set[y_set == j, 1],
        c = ListedColormap(('red', 'green'))(i), label = j)
mtp.title('SVM classifier (Test set)')
mtp.xlabel('Age')
mtp.ylabel('Estimated Salary')
mtp.legend()
mtp.show()

输出:

通过执行以上代码,我们将获得以下输出:

如上图所示,SVM分类器已将用户分为两个区域(已购买或未购买)。购买SUV的用户位于带有红色散点的红色区域。未购买SUV的用户位于绿色分散点的绿色区域。超平面将这两个类别分为“已购买”和“未购买”变量。