支持向量机SVM
2018-12-29 本文已影响0人
不会忘的名字
支持向量机SVM(Support Vector Machine)
【关键词】支持向量,最大几何间隔,拉格朗日乘子法
一、支持向量机的原理
Support Vector Machine。支持向量机,其含义是通过支持向量运算的分类器。其中“机”的意思是机器,可以理解为分类器。
那么什么是支持向量呢?在求解的过程中,会发现只根据部分数据就可以确定分类器,这些数据称为支持向量。
见下图,在一个二维环境中,其中点R,S,G点和其它靠近中间黑线的点可以看作为支持向量,它们可以决定分类器,也就是黑线的具体参数。
解决的问题:
- 线性分类
在训练数据中,每个数据都有n个的属性和一个二类类别标志,我们可以认为这些数据在一个n维空间里。我们的目标是找到一个n-1维的超平面(hyperplane),这个超平面可以将数据分成两部分,每部分数据都属于同一个类别。
其实这样的超平面有很多,我们要找到一个最佳的。因此,增加一个约束条件:这个超平面到每边最近数据点的距离是最大的。也成为最大间隔超平面(maximum-margin hyperplane)。这个分类器也成为最大间隔分类器(maximum-margin classifier)。
支持向量机是一个二类分类器。
- 非线性分类
SVM的一个优势是支持非线性分类。它结合使用拉格朗日乘子法和KKT条件,以及核函数可以产生非线性分类器。
SVM的目的是要找到一个线性分类的最佳超平面 f(x)=xw+b=0。求 w 和 b。
首先通过两个分类的最近点,找到f(x)的约束条件。
有了约束条件,就可以通过拉格朗日乘子法和KKT条件来求解,这时,问题变成了求拉格朗日乘子αi 和 b。
对于异常点的情况,加入松弛变量ξ来处理。
非线性分类的问题:映射到高维度、使用核函数。
二.实战
1.画出决策边界
- 导包sklearn.svm
import numpy as np
from sklearn.svm import SVC,SVR
import matplotlib.pyplot as plt
%matplotlib inline
- 随机生成数据,并且进行训练np.r_[]
生成数据
from sklearn.datasets import make_blobs
data, target = make_blobs(centers=2)
plt.scatter(data[:,0], data[:,1], c=target)
生成数据图片.png
- 训练模型,并训练
**如果是直线可以划分开的话,需要指定线性的核函数**
svc = SVC(kernel='linear')
svc.fit(data, target)
out:SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto', kernel='linear',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
# 支持向量
sv = svc.support_vectors_
sv
out:array([[4.23522683, 9.19250893],
[6.23760702, 7.88434105],
[2.00382811, 3.16498141]])
- 提取系数获取斜率
# 斜率
w1, w2 = svc.coef_[0,0], svc.coef_[0,1]
display(w1, w2)
out:-0.17459676838526306
-0.26715404312361524
- 线性方程的截距
# 截距
b = svc.intercept_
# 画出支持向量的点 alpha透明度
plt.scatter(data[:,0], data[:,1], c=target)
plt.scatter(sv[:,0], sv[:,1],c=[0,1,2] ,cmap='rainbow', s=200, alpha=0.5)
支持向量显示点.png
# 实际的方程:
y = w1*x1 + w2*x2 + b # 这是一个空间坐标方程3个未知数
# 令y=0, 压缩到2维上.直线可以划分开,求2维上线性方程
0 = w1*x + w2*y + b
x = np.linspace(0, 8, 100)
y = -w1/w2 * x - b/w2
# 画出分割线
plt.scatter(data[:,0], data[:,1], c=target)
plt.scatter(sv[:,0], sv[:,1],c=[0,1,2] ,cmap='rainbow', s=200, alpha=0.5)
plt.plot(x, y, c='r')
分割线图.png
# 求上边界
# 已知斜率,和线上的点,求截距
# y_up = x_up * (-w1/w2) + b_up
b_up = y_up + x_up*(w1/w2)
b_up = sv[0,1] + sv[0,0]* (w1/w2)
b_up
out:11.960413579746653
plt.scatter(data[:,0], data[:,1], c=target)
plt.scatter(sv[:,0], sv[:,1],c=[0,1,2] ,cmap='rainbow', s=200, alpha=0.5)
plt.plot(x, y, c='r')
# 画上边界
plt.plot(x, -x*w1/w2 + b_up, c='k')
包含上边界图.png
# 下截距
y_down = -(w1/w2) * x_down + b_down
b_down = y_down + w1/w2*x_down
b_down = sv[2,1] + w1/w2 * sv[2,0]
b_down
out:4.474570094543953
plt.scatter(data[:,0], data[:,1], c=target)
plt.scatter(sv[:,0], sv[:,1],c=[0,1,2] ,cmap='rainbow', s=200, alpha=0.5)
plt.plot(x, y, c='r')
# 画上边界
plt.plot(x, -x*w1/w2 + b_up, c='k')
# 画出下边界
plt.plot(x, -x*w1/w2 + b_down, c='b')
画出下边界完成所有画图.png
注:先画出分割线,求得斜率. 在分别求得上下边界的截距画出上下边界的直线.
2、SVM分离坐标点
- 导包
import numpy as np
from sklearn.svm import SVC
import matplotlib.pyplot as plt
%matplotlib inline
- 生成数据
# 生成一堆随机点.
X_train = np.random.randn(300, 2)
plt.scatter(X_train[:,0], X_train[:,1])
随机生成的正态数据.png
# python中认为空字符串, 空列表,空字典,空集合,空的东西,还有0,都是False,除此之外都是True.
n1 = np.array([0,2,3])
n2 = np.array([2,3,4])
np.logical_xor(n1,n2)
out:array([ True, False, False])
# 借助异或的思想,实现数据的分类
target = np.logical_xor(X_train[:,0]>0, X_train[:,1]>0)
# 实际上python会把True当成1,False当成0.
plt.scatter(X_train[:,0], X_train[:,1], c=target)
异或分类数据.png
- 训练
svc = SVC()
svc.fit(X_train, target)
out:SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
- 创造-3到3范围的点以及meshgrid
xmin, xmax = X_train[:,0].min(), X_train[:,0].max()
ymin, ymax = X_train[:,1].min(), X_train[:,1].max()
x,y = np.linspace(xmin, xmax, 1000), np.linspace(ymin, ymax,1000)
X,Y = np.meshgrid(x,y)
X_test = np.c_[X.ravel(), Y.ravel()]
- 绘制图形
绘制测试点到分离超平面的距离(decision_function)
绘制轮廓线
绘制训练点
distance = svc.decision_function(X_test)
# 在超平面之上面的点
(distance>0).sum()
out:511785
# 在超平面之下面的点
(distance<0).sum()
out:488215
- 画图
plt.figure(figsize=(8,8))
Z = distance.reshape(1000, 1000)
plt.show(Z, cmap='PuOr_r', extent=[xmin, xmax, ymin, ymax])
plt.contour(X, Y, Z)
plt.scatter(X_train[:,0], X_train[:,1], c=target)
类似等高线的超平面图.png
3、使用多种核函数对iris数据集进行分类
- 导包,获取鸢尾花数据
from sklearn.svm import SVC
from sklearn.datasets import load_iris
iris = load_iris()
data = iris.data[:,0:2]
target = iris.target
- 图片背景点
xmin, xmax = data[:,0].min(), data[:,0].max()
ymin, ymax = data[:,1].min(), data[:,1].max()
x,y = np.linspace(xmin, xmax, 1000), np.linspace(ymin, ymax, 1000)
X, Y = np.meshgrid(x,y)
X_test = np.c_[X.ravel(),Y.ravel()]
- 提取数据只提取两个特征,方便画图
创建支持向量机的模型(kernel):'linear'线性, 'poly'(多项式),
'rbf'(Radial Basis Function:基于半径函数).
LinearSVC 是优化过的对大数据里有更好效果的线性核函数
# 线性核函数
svc = SVC(kernel='linear')
svc.fit(data, target)
# 预测
y_linear = svc.predict(X_test)
# 半径
svc = SVC(kernel='rbf')
svc.fit(data, target)
y_rbf = svc.predict(X_test)
# 多项式
svc = SVC(kernel='poly')
svc.fit(data, target)
y_poly = svc.predict(X_test)
from sklearn.svm import LinearSVC
# LinearSVC 是优化过的对大数据里有更好效果的线性核函数
svc_linear = LinearSVC()
svc_linear.fit(data, target)
y_Linear = svc_linear.predict(X_test)
- 画4个图,做一个横向对比
# 画4个图,做一个横向对比
plt.figure(figsize=(4* 5,4* 4))
axes1 = plt.subplot(2,2,1)
axes1.pcolormesh(X,Y, y_linear.reshape(1000,1000))
axes1.scatter(data[:,0], data[:,1], c=target, cmap='rainbow')
axes2 = plt.subplot(2,2,2)
axes2.pcolormesh(X,Y, y_Linear.reshape(1000,1000))
axes2.scatter(data[:,0], data[:,1], c=target, cmap='rainbow')
axes3 = plt.subplot(2,2,3)
axes3.pcolormesh(X,Y, y_rbf.reshape(1000,1000))
axes3.scatter(data[:,0], data[:,1], c=target, cmap='rainbow')
axes4 = plt.subplot(2,2,4)
axes4.pcolormesh(X,Y, y_poly.reshape(1000,1000))
axes4.scatter(data[:,0], data[:,1], c=target, cmap='rainbow')
四种对比图.png
4、使用SVM多种核函数进行回归
- 导包
from sklearn.svm import SVR
- 自定义样本点rand,并且生成sin值
X_train = np.random.rand(100) * 10
y_train = np.sin(X_train)
plt.scatter(X_train, y_train)
自定义生成的sin值.png
- 数据加噪
y_train[::4] += 0.3 * np.random.randn(25)
plt.scatter(X_train, y_train)
加噪声的图片.png
- 建立模型,训练数据,并预测数据,预测训练数据就行
# 预测数据
X_test = np.linspace(0,10, 1000).reshape(-1,1)
# 线性核函数
svr_linear = SVR(kernel='linear')
svr_linear.fit(X_train.reshape(-1,1),y_train)
# 预测
y_linear = svr_linear.predict(X_test)
svr_rbf = SVR(kernel='rbf')
svr_rbf.fit(X_train.reshape(-1,1),y_train)
# 预测
y_rbf = svr_rbf.predict(X_test)
svr_poly = SVR(kernel='poly')
svr_poly.fit(X_train.reshape(-1,1),y_train)
# 预测
y_poly = svr_poly.predict(X_test)
- 绘制图形,观察三种支持向量机内核不同
plt.figure(figsize=(12,9))
plt.plot(X_test, y_linear, label='linear')
plt.plot(X_test, y_rbf, label='rbf')
plt.plot(X_test, y_poly, label='poly')
plt.scatter(X_train, y_train)
plt.legend()
拟合曲线.png
- 计算拟合得分
svr_rbf.score(X_train.reshape(-1,1) ,y_train)
out:0.9079373035139664
svr_linear.score(X_train.reshape(-1,1) ,y_train)
out:-0.0016745395323372048
svr_poly.score(X_train.reshape(-1,1) ,y_train)
out:0.011116368287051204
注:从上面拟合曲线和拟合得分来看, 基于半径的核函数, 回归拟合程度最好.