基本概念
1、支持向量机、支持向量、决策面、分类间隔
在感知机模型中,我们可以找到多个可以分类的超平面将数据分开,并且优化时希望所有的点都被准确分类。但是实际上离超平面很远的点已经被正确分类,它对超平面的位置没有影响。我们最关心是那些离超平面很近的点,这些点很容易被误分类。如果我们可以让离超平面比较近的点尽可能的远离超平面,最大化几何间隔,那么我们的分类效果会更好一些。SVM的思想起源正起于此。
如下图所示,分离超平面为
(
w
T
x
+
b
=
0
)
(w^Tx+b=0)
(wTx+b=0),如果所有的样本不光可以被超平面分开,还和超平面保持一定的函数距离(下图函数距离为1),那么这样的分类超平面是比感知机的分类超平面优的。可以证明,这样的超平面只有一个,这个超平面也称为决策面。和超平面平行的保持一定的函数距离的这两个超平面对应的向量,我们定义为支持向量,在二维平面下,它是一个点,也就是说支持向量参与决策面的计算。支持向量到决策面的最小距离称为分类间隔。如下图虚线所示。
2、目标函数及求解
参照https://zhuanlan.zhihu.com/p/150702652,个人觉得写的不错。
3、非线性支持向量机、核函数
假设样本数据是完全线性可分的,那么学习到的模型就可以称之为硬间隔支持向量机,即硬间隔就是指完全正确的分类,不存在错误的情况。
但是在真实的世界中,数据往往都不是那么“干净”的,存在异常数据是再正常不过了,此时就需要软间隔。软间隔就是指允许一部分数据样本分类错误,从而使得训练的模型可以满足绝大部分其他样本。
还存在另外一种情况,就是非线性的数据集。我们前面讨论的都是线性情况下的分类,那么对于非线性的情况,SVM 也是支持的,就是非线性支持向量机。
比如该类数据集,任何线性模型都没有办法处理,SVM 也是不可用的。此时,我们就需要引入一个新的概念:核函数。它可以将样本从原始的空间映射到一个更高纬度的空间中,从而使得在新的空间中样本是线性可分的,这样就可以继续使用 SVM 来做分类了。
在非线性 SVM 中,核函数的选择是影响 SVM 的最大因素。常用的核函数有线性核、多项式核、高斯核、拉普拉斯核,sigmoid 核等,或者是使用它们的组合核函数。通过这些核函数的转换,我们就可以把样本空间投射到新的高维度空间中。
测试代码
import numpy as np
from sklearn import datasets, model_selection, svm
from matplotlib import pyplot as plt
dataset = datasets.load_iris()
data, labels = dataset["data"], dataset["target"]
train_data, test_data, train_labels, test_labels = model_selection.train_test_split(data, labels, test_size=0.2)
train_data, test_data = train_data[:, :2], test_data[:, :2]
train_labels, test_labels = np.where(train_labels > 0, 1, 0), np.where(test_labels > 0, 1, 0)
# 核函数
kernels = ["linear", "poly", "rbf"]
x, y = train_data[:, 0], train_data[:, 1]
x_min, x_max, y_min, y_max = np.min(x), np.max(x), np.min(y), np.max(y)
plt.figure(figsize=(15, 15))
plt.subplot(2, 2, 1)
plt.title("raw")
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks([])
plt.yticks([])
plt.scatter(x, y, s=30, c=train_labels)
for i, kernel in enumerate(kernels):
model = svm.SVC(kernel=kernel)
model.fit(train_data, train_labels)
plt.subplot(2, 2, i + 2)
plt.title(kernel)
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)
plt.xticks([])
plt.yticks([])
XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j]
Z = model.decision_function(np.c_[XX.ravel(), YY.ravel()])
Z = Z.reshape(XX.shape)
plt.pcolormesh(XX, YY, Z > 0, cmap=plt.cm.Paired)
plt.contour(XX, YY, Z, colors=['black', 'k', 'white'], linestyles=['--', '-', '--'], levels=[-.5, 0, .5])
plt.scatter(x, y, s=30, c=train_labels)
X, Y = model.support_vectors_[:, 0], model.support_vectors_[:, 1]
plt.scatter(X, Y, marker='*')
plt.show()
不同核函数下的分类平面: