Python机器学习之支持向量机

引言

SVM的基本概念

分隔超平面:将数据集分割开来的直线叫做分隔超平面。
超平面:如果数据集是N维的,那么就需要N-1维的某对象来对数据进行分割。该对象叫做超平面,也就是分类的决策边界。
间隔:一个点到分割面的距离,称为点相对于分割面的距离。
数据集中所有的点到分割面的最小间隔的2倍,称为分类器或数据集的间隔。
最大间隔:SVM分类器是要找最大的数据集间隔。
支持向量:坐落在数据边际的两边超平面上的点被称为支持向量

一、支持向量机的直观理解

import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.datasets import make_blobs

#创建50个点,分为两类
X, y = make_blobs(n_samples=50, centers=2, random_state=6)

#创建一个线性内核的支持向量机
svm1 = svm.SVC(kernel='linear', C=1000)
svm1.fit(X, y)

#把数据点画出来
plt.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=plt.cm.Paired)

#建立图像坐标
ax = plt.gca()
xlim = ax.get_xlim() #返回坐标的上下限
ylim = ax.get_ylim()

#生成两个等差数列
xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
XX, YY = np.meshgrid(xx, yy)
xy = np.vstack([XX.ravel(), YY.ravel()]).T
Z = svm1.decision_function(xy).reshape(XX.shape) #计算样本点到分割超平面的函数距离

#把分类的决定边界画出来
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--']) #画出等高线图
ax.scatter(svm1.support_vectors_[:, 0], svm1.support_vectors_[:, 1], s=100, linewidth=1, facecolors='none') #support_vectors_ 所有的支持向量
plt.show()

如图所示,分类器两侧有两条虚线,压在虚线上的点,就是支持向量。本例子采用的方法是“最大间隔超平面”,指的是说中间这条实线(在高维数据中是一个超平面),和所有支持向量之间的距离,都是最大的。


7.1SVM_linear.png

修改SVM 的内核,换成RBF,即修改以下代码:

#创建一个线性内核的支持向量机
svm1 = svm.SVC(kernel='rbf', C=1000)
svm1.fit(X, y)

如图所示,


7.1SVM_rbf.png

注释1:

函数原型:matplotlib.pyplot.gca()

获得当前的Axes对象ax
参考:
《python matplotlib.pyplot.gca() 函数的作用(获得当前的Axes对象【Get Current Axes】)》
matplotlib绘图——再谈axes和pyplot方法》
注释2:
函数原型:sklearn.svm.svc(C=1.0, kernel='rbf', degree=3, gamma='auto',
coef0=0.0, shrinking=True, probability=False,
tol=1e-3, cache_size=200, class_weight=None,
verbose=False, max_iter=-1, decision_function_shape='ovr', random_state=None)
参数解释
C: float参数 默认值为1.0.
错误项的惩罚系数。C越大,即对分错样本的惩罚程度越大,因此在训练样本中准确率越高,但是泛化能力降低,也就是对测试数据的分类准确率降低。相反,减小C的话,容许训练样本中有一些误分类错误样本,泛化能力强。对于训练样本带有噪声的情况,一般采用后者,把训练样本集中错误分类的样本作为噪声。
kernel: str参数 默认为‘rbf’.算法中采用的核函数类型,可选参数有:
  ‘linear’:线性核函数
‘  poly’:多项式核函数
  ‘rbf’:径像核函数/高斯核
  ‘sigmoid’:sigmod核函数
  ‘precomputed’:核矩阵.precomputed表示自己提前计算好核函数矩阵,这时候算法内部就不再用核函数去计算核矩阵,而是直接用你给的核矩阵。
  还有一点需要说明,除了上面限定的核函数外,还可以给出自己定义的核函数,其实内部就是用你自己定义的核函数来计算核矩阵。
degree: int型参数 默认为3.这个参数只对多项式核函数有用,是指多项式核函数的阶数n
如果给的核函数参数是其他核函数,则会自动忽略该参数。
gamma: float参数 默认为auto.核函数系数,只对‘rbf’,‘poly’,‘sigmod’有效。
如果gamma为auto,代表其值为样本特征数的倒数,即1/n_features.
coef0: float参数 默认为0.0.核函数中的独立项,只有对‘poly’和‘sigmod’核函数有用,是指其中的参数c
probability: bool参数 默认为False.是否启用概率估计。 这必须在调用fit()之前启用,并且会fit()方法速度变慢。
shrinking: bool参数 默认为True.是否采用启发式收缩方式
tol: float参数 默认为1e^-3.svm停止训练的误差精度
cache_size: float参数 默认为200.指定训练所需要的内存,以MB为单位,默认为200MB。
class_weight: 字典类型或者‘balance’字符串。默认为None.给每个类别分别设置不同的惩罚参数C,如果没有给,则会给所有类别都给C=1,即前面参数指出的参数C.如果给定参数‘balance’,则使用y的值自动调整与输入数据中的类频率成反比的权重。
verbose: bool参数 默认为False.是否启用详细输出。 此设置利用libsvm中的每个进程运行时设置,如果启用,可能无法在多线程上下文中正常工作。一般情况都设为False,不用管它。
max_iter: int参数 默认为-1.最大迭代次数,如果为-1,表示不限制.
random_state: int型参数 默认为None.伪随机数发生器的种子,在混洗数据时用于概率估计。
属性
svc.n_support_:各类各有多少个支持向量
svc.support_:各类的支持向量在训练样本中的索引
svc.support_vectors_:各类所有的支持向量
参考:《SVM基本概要与sklearn.svm.svc 参数说明》
注释3:
[《Python+Matplotlib画contour图》](https://finthon.com/python-matplotlib-contour/

二、不同核函数的SVM对比

说明:linearSVM是一种使用了线性内核的SVM算法,不过linearSVM不支持对核函数进行修改。
使用dataset的红酒数据

#对比不同的SVM
from sklearn.datasets import load_wine
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm

#定义画图函数
def make_meshgrid(x, y, h= .02):
    x_min, x_max = x.min() - 1, x.max() - 1
    y_min, y_max = y.min() - 1, y.max() - 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    return xx, yy

#定义绘制等高线的函数
def plot_countours(ax, clf, xx, yy, **params):
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    out = ax.contourf(xx, yy, Z, **params)
    return out

#导入红酒数据
wine = load_wine()
#选取前两个特征
X = wine.data[:, :2]
y = wine.target

C = 1.0 #SVM正则化参数
models = (svm.SVC(kernel='linear', C=C),
          svm.LinearSVC(C=C),
          svm.SVC(kernel='rbf', gamma=0.7, C=C),
          svm.SVC(kernel='poly', degree=3, C=C))

models = (clf.fit(X, y) for clf in models)

#设置图题
titles = ('SVC with linear kernel',
          'LinearSVC(linear kernal)',
          'SVC with RBF kernal',
          'SVC with polynomial(degree 3) kernal')

#设定子图形的个数和排列方式
fig, sub = plt.subplots(2, 2)
plt.subplots_adjust(wspace=0.4, hspace=0.4) #wspace, hspace:子图之间的横向间距、纵向间距分别与子图平均宽度、平均高度的比值。

#画图,使用上面自定义的画 图函数
X0, X1 = X[:, 0], X[:, 1]
xx, yy = make_meshgrid(X0, X1)

for clf, title, ax in zip(models, titles, sub.flatten()):
    plot_countours(ax, clf, xx, yy, cmap=plt.cm.plasma, alpha=0.8)
    ax.scatter(X0, X1, c=y, cmap=plt.cm.plasma, s=20, edgecolors='k')
    ax.set_xlim(xx.min(), xx.max())
    ax.set_ylim(yy.min(), yy.max())
    ax.set_xlabel('Feature 0')
    ax.set_ylabel('Feature 1')
    ax.set_xticks(())
    ax.set_yticks(())
    ax.set_title(title)
plt.show()

从图中可以看出来:
1.LinearSVC 和线性内核的 SVC 得到的结果非常近似。但仍有差别,原因之一是,LinearSVC对 L2范数进行优化,而线性内核的SVC是对L1范数进行优化;
2.RBF 内核的 SVC 和 polynomial 内核的 SVC 分类器的决定边界不是线性的,更加弹性。决定他们形状的,是它们的参数。polynomial 内核的 SVC中,起决定作用的参数是 degree 和 正则化参数 C,上述代码中使用的 degree是3 ,也就是对原始数据集的特征乘3次方操作。RBF 内核的 SVC中起决定作用的是正则化参数 C 和参数 gamma。


7.2SVM_diff.png

注释1:

《Python tips: 什么是 *args 和 **kwargs?》

注释2:

np.r_是按列连接两个矩阵,就是把两矩阵上下相加,要求列数相等。
np.c_是按行连接两个矩阵,就是把两矩阵左右相加,要求行数相等

三、支持向量机的gamma参数调节

仍旧使用红酒数据,调节gamma 参数值,查看对 RBF 内核的 SVC有什么影响。

#调节gamma 参数值,查看对 RBF 内核的 SVC有什么影响
from sklearn.datasets import load_wine
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm

#定义画图函数
def make_meshgrid(x, y, h= .02):
    x_min, x_max = x.min() - 1, x.max() - 1
    y_min, y_max = y.min() - 1, y.max() - 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    return xx, yy

#定义绘制等高线的函数
def plot_countours(ax, clf, xx, yy, **params):
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    out = ax.contourf(xx, yy, Z, **params)
    return out

#导入红酒数据
wine = load_wine()
#选取前两个特征
X = wine.data[:, :2]
y = wine.target

C = 1.0 #SVM正则化参数
models = (svm.SVC(kernel='rbf', gamma=0.1, C=C),
          svm.SVC(kernel='rbf', gamma=1, C=C),
          svm.SVC(kernel='rbf', gamma=10, C=C))

models = (clf.fit(X, y) for clf in models)

#设置图题
titles = ('gamma = 0.1',
          'gamma = 1',
          'gamma = 10')

#设定子图形的个数和排列方式
fig, sub = plt.subplots(1, 3, figsize = (10, 3))

#画图,使用上面自定义的画 图函数
X0, X1 = X[:, 0], X[:, 1]
xx, yy = make_meshgrid(X0, X1)

for clf, title, ax in zip(models, titles, sub.flatten()):
    plot_countours(ax, clf, xx, yy, cmap=plt.cm.plasma, alpha=0.8)
    ax.scatter(X0, X1, c=y, cmap=plt.cm.plasma, s=20, edgecolors='k')
    ax.set_xlim(xx.min(), xx.max())
    ax.set_ylim(yy.min(), yy.max())
    ax.set_xlabel('Feature 0')
    ax.set_ylabel('Feature 1')
    ax.set_xticks(())
    ax.set_yticks(())
    ax.set_title(title)
plt.show()

从图中可以看出来:
1.gamma值越小,RBF内核的直径越大,有更多的点被圈入决策边界中,决策边界也越平滑
2.随着gamma参数的增加,模型更倾向于把每一个点都放到相应的决策边界中,模型的复杂度也相应提高了
3.gamma值越小,模型更倾向于欠拟合;gamma 值越大,模型更倾向于欠拟合
4.正则化参数C,越小,模型越受限,即单个数据点对模型的影响越小;C 越大,每个数据点对模型的影响就越大,模型就会更加复杂


7.3RBF_gamma.png

四、支持向量机的优势与不足

优势:

  • 1.可以在数据特征很少的情况下生成非常复杂的决定边界。即 SVM 应对高维数据集和低维数据集都可,但前提是数据规模不太大
  • 2.数据样本特征的测度比较接近。例如图像识别领域,或者样本特征数和样本数比较接近的时候,SVM 游刃有余。
    参数
    不足:
  • 1.样本数量超过10W 的话,SVM会非常耗费时间和内存。
  • 2.对于数据预处理和参数的调节要求很高。

SVM 算法中,有3个重要参数调节:

  • 1.核函数的选择
  • 2.核函数的参数,例如 RBF 的 gamma 值,用来调节内核宽度,gamma 值和 C 值一起控制模型的复杂度,数值越大模型越复杂,往往需要一起调节。
  • 3.正则化参数 C
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342