CS_sklearn_2 SVM_1

SVM(support vector machines)

此文比较详细的介绍了SVM在sklearn中的应用和一些相关概念
本文以案例为主,辅以少量讲解,需要读者自行理解

概念

  VC维
  VC 维是衡量函数类的复杂度的一种方式,通过评估函数类中函数的弯曲程度实现。举个例子,假设 { f ( x , α ) } \{f(x,\alpha)\} {f(x,α)}为线性指示函数类 I ( α 0 + α 1 T x > 0 ) ) I(\alpha_0 + \alpha_1^T x \gt 0)) I(α0+α1Tx>0))。直观理解,该函数通过直线 将平面分成两部分,一侧取值为0,一侧取值为1。如果该函数的VC维为 ,则表明在平面上任意给出 个点的位置及取值(0或1),总存在一条直线 将这 个点分开,一侧取0,一侧取1,也就是存在能满足这 个点的函数 。结论是,平面中线性指示函数的VC维等于3,也就是平面中任意3个点(无论如何取值)总能被一条直线分开,而四个点却不行,如下图
在这里插入图片描述

详细讲解推荐看台湾大学林轩田老师的视频
推荐阅读这篇笔记https://blog.csdn.net/red_stone1/article/details/71191232

  超平面
  在几何中,超平面是一个空间的子空间,它是维度比所在空间小一维的空间。 如果数据空间本身是三维的, 则其超平面是二维平面,而如果数据空间本身是二维的,则其超平面是一维的直线。
  在二分类问题中,如果一个超平面能够将数据划分为两个集合,其中每个集合中包含单独的一个类别,我们就说这个超平面是数据的“决策边界”。

  SVM
  svm主要就是寻找边际最大的决策边界 0 = w T + b 0 = w^T + b 0=wT+b

  支持向量
  在支持向量机中,距离超平面bai最近的且满足一定条件的du几个训练样本点被称zhi为支持向量。
在这里插入图片描述

Sample 1 linear

  先展示一个线性核函数的分类案例,使用sklearn中的make_blobs函数生成一些聚类数据
  导入模块和数据

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

做一个散点图看看数据分布

X,y = make_blobs(n_samples = 50,centers = 2,random_state = 0,cluster_std = 0.6)
plt.figure()          #添加一个窗口 
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap = "rainbow")
plt.xticks([]) # 固定x轴
plt.yticks([])
plt.show()

在这里插入图片描述

  接下来是为了画决策边界做准备的,他用了很巧妙的方法,先在画板上定义了许多等间距的网格点,再把网格点的x和y的数据做成shape是(900,2)的xy变量,把他当作test datasets 放到clf,decision_function() 当中,这个函数返回的是每个样本点到决策边界的距离,这样把xy放到里面就能得到网格上每个点到决策边界的距离,再把这个数据当作Z,做等高线。

xlim = ax.get_xlim() # x轴坐标的范围
ylim = ax.get_ylim()
print(xlim)

# 形成沿x轴,y轴的等差数列 分成30份
axisx = np.linspace(xlim[0],xlim[1], 30)
axisy = np.linspace(ylim[0],ylim[1], 30)
#形成网格数据
axisx,axisy = np.meshgrid(axisx,axisy)
# print(axisx)


# ravel()是降维函数
# np.vstack([axisx.ravel(), axisy.ravel()]).shape == (2, 900)
# xy就是两列数轴的数据 xy.shape == (900,2) 
# np.vstack() 可以代替成 np.array() 
xy = np.vstack([axisx.ravel(), axisy.ravel()]).T

  理解函数meshgrid和vstack的作用


#理解函数meshgrid和vstack的作用
a = np.array([1,2,3])
b = np.array([7,8])
#两两组合,会得到多少个坐标?
#答案是6个,分别是 (1,7),(2,7),(3,7),(1,8),(2,8),(3,8)
v1,v2 = np.meshgrid(a,b)
print(v1)
print(v2)

  开始搭建SVC模型

# 建模
clf = SVC(kernel= "linear").fit(X,y)
# clf.decision_function(X).shape == (900,)
# clf.decision_function(xy) 得到网格点上每一个点到决策边界的距离
# clf.decision_function(X) 返回每个样本到决策边界的距离
# 把距离数据转换成axisx的shape,这是由于画图的函数contour要求Z的结构必须与X和Y保持一致
Z = clf.decision_function(xy).reshape(axisx.shape) 

# y == 0的数据恰好距离都是负的
print(clf.decision_function(X))
# [ 1.40603714  1.3591769  -2.51058235 -2.13942243  2.18430606  3.60280644
#   3.79864307  0.95048419  2.06722659 -4.36242933 -3.33917354 -3.33016044
#  -2.80610364  2.78359637 -1.78232701 -1.7657915  -2.3183929   3.0466215
#  -0.99999987 -2.86848992  2.63755919  1.89023869  2.25718297  2.62966853
#   2.41900855 -0.9999994  -2.22302791 -3.40694626  2.78168963 -1.44976041
#   1.64660828 -2.95807889 -2.72951819 -2.56144709 -3.51816073  2.33579112
#   2.11037259 -3.69706531  3.75909944 -1.60942589  1.81798745 -2.25885574
#   3.7399511   1.52000771 -2.3538635   1.44881542  1.06318842 -1.48566549
#   2.73630505 -2.69205979]
print(clf.decision_function(X)[y == 0]) 
# [-2.51058235 -2.13942243 -4.36242933 -3.33917354 -3.33016044 -2.80610364
#  -1.78232701 -1.7657915  -2.3183929  -0.99999987 -2.86848992 -0.9999994
#  -2.22302791 -3.40694626 -1.44976041 -2.95807889 -2.72951819 -2.56144709
#  -3.51816073 -3.69706531 -1.60942589 -2.25885574 -2.3538635  -1.48566549
#  -2.69205979]


  画决策边界

#首先要有散点图
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap = "rainbow")
axx = plt.gca() # 获取当前子图如果不存在则创建新的子图
#画决策边界和平行于决策边界的超平面
axx.contour(axisx,axisy,Z
           ,colors="k"
           ,levels=[-1,0,1] #画三条等高线,分别是Z == -1,Z == 0和Z == 1的三条线
           ,alpha=0.5#透明度
           ,linestyles=["--","-","--"])
 
axx.set_xlim(xlim)#设置x轴取值
axx.set_ylim(ylim)
# plt.show()

在这里插入图片描述

 随便找一个点,把那个点变成黑色,clf.decision_function([[X_t[0],X_t[1]]])显示了那个点到决策边界的距离。

x_c = 1
X_t = [X[x_c,0],X[x_c,1]]
plt.scatter(X[:,0],X[:,1],c = y ,s = 50 ,cmap= "rainbow")
plt.scatter(X_t[0],X_t[1],c = "black" ,s = 50 ,cmap = "rainbow")
# print(X[10,0],X[10,1])
print(clf.decision_function([[X_t[0],X_t[1]]]))
print(y[x_c])

在这里插入图片描述

  画出那一个点的等高线

clf.decision_function(X[10].reshape(1,2))
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plt.scatter(X[10,0],X[10,1],c = "black" ,s = 50 ,cmap = "rainbow")
ax = plt.gca()

print(X[10])
print(Z[10,0])
ax.contour(axisx,axisy,Z
            ,colors="k"
            ,levels=[-3.33917354]
            ,alpha=0.5
            ,linestyles=["--"])

在这里插入图片描述

  把上面的过程都封装进一个函数里

# 将上述过程包装成一个函数
def plot_svc_decision_function(model,ax = None):
    if ax is None:
        ax = plt.gca()
        
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    
    
    # 形成沿x轴,y轴的等差数列
    axisx = np.linspace(xlim[0],xlim[1], 30)
    axisy = np.linspace(ylim[0],ylim[1], 30)
    axisx,axisy = np.meshgrid(axisx,axisy)
    xy = np.vstack([axisx.ravel(), axisy.ravel()]).T
    
    #画出决策边界
    P = model.decision_function(xy).reshape(axisx.shape)
    print(model.decision_function(xy).reshape(axisx.shape).shape
    )
    ax.contour(axisx, axisy, P,colors="k",levels=[-1,0,1],alpha=0.5,linestyles=["--","-","--"]) 
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)
    
#则整个绘图过程可以写作:
clf = SVC(kernel = "linear").fit(X,y)
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plot_svc_decision_function(clf)
    

  模型的一些训练之后的参数

print(clf.predict(X))
# [1 1 0 0 1 1 1 1 1 0 0 0 0 1 0 0 0 1 0 0 1 1 1 1 1 0 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 0 1 1 0 1 1 0 1 0]
print(clf.score(X,y)) # 1.0

print(clf.support_vectors_)
# [[0.44359863 3.11530945]
#  [2.33812285 3.43116792]
#  [2.06156753 1.96918596]]
print(clf.support_) #[18 25  7]

Sample 2 nonlinear

  在非线性数据的情况下就要使用非线性的核函数了,上文中的一些包也要引入,在上文中包的基础上引入下面这个包,生成一些环形数据

from sklearn.datasets import make_circles
X,y = make_circles(100,factor = 0.1 ,noise = 0.1)
plt.scatter(X[:,0],X[:,1],c = y,s = 50,cmap = "rainbow")

在这里插入图片描述
  再次使用线性核函数就会变得一塌糊涂

clf = SVC(kernel = "linear").fit(X,y)
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="jet")
plot_svc_decision_function(clf)

在这里插入图片描述
  将数据映射到更高维度,就可以直观看出分界

#定义一个由x计算出来的新维度r 高度
r = np.exp(-(X**2).sum(1))
 
rlim = np.linspace(min(r),max(r),100)
 
from mpl_toolkits import mplot3d
 
#定义一个绘制三维图像的函数
#elev表示上下旋转的角度
#azim表示平行旋转的角度
def plot_3D(elev=30,azim=30,X=X,y=y):
    ax = plt.subplot(projection="3d")
    ax.scatter3D(X[:,0],X[:,1],r,c=y,s=50,cmap='rainbow')
    ax.view_init(elev=elev,azim=azim)
    ax.set_xlabel("x")
    ax.set_ylabel("y")
    ax.set_zlabel("r")
    plt.show()
    
plot_3D()

在这里插入图片描述
  使用高斯径向基核函数

clf = SVC(kernel= "rbf").fit(X,y) # 不使用线性核函数
plt.scatter(X[:,0],X[:,1],c=y,s=50,cmap="rainbow")
plot_svc_decision_function(clf)

在这里插入图片描述

Sample 3 Kernel function

  除了"linear"以外的核函数都能够处理非线性情况,那究竟什么时候选择哪一个核函数呢?遗憾的是,关于核函数 在不同数据集上的研究甚少,谷歌学术上的论文中也没有几篇是研究核函数在SVM中的运用的,更多的是关于核函 数在深度学习,神经网络中如何使用。在sklearn中,也没有提供任何关于如何选取核函数的信息。
  但无论如何,我们还是可以通过在不同的核函数中循环去找寻最佳的核函数来对核函数进行一个选取。接下来我们 就通过一个例子,来探索一下不同数据集上核函数的表现。我们现在有一系列线性或非线性可分的数据,我们希望通过绘制SVC在不同核函数下的决策边界并计算SVC在不同核函数下分类准确率来观察核函数的效用。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn import svm#from sklearn.svm import SVC  两者都可以
from sklearn.datasets import make_circles, make_moons, make_blobs,make_classification
n_samples = 100
 
datasets = [
    make_moons(n_samples=n_samples, noise=0.2, random_state=0),
    make_circles(n_samples=n_samples, noise=0.2, factor=0.5, random_state=1),
    make_blobs(n_samples=n_samples, centers=2, random_state=5),#分簇的数据集
    make_classification(n_samples=n_samples,n_features = 2,n_informative=2,n_redundant=0, random_state=5)
                #n_features:特征数,n_informative:带信息的特征数,n_redundant:不带信息的特征数
    ]
 
Kernel = ["linear","poly","rbf","sigmoid"]
 
fig1,ax1 = plt.subplots(nrows=2, ncols=2,figsize=(10,8))
axes1 = ax1.flatten()
#四个数据集分别是什么样子呢?
for id,(X,Y) in enumerate(datasets):
    axes1[id].scatter(X[:,0],X[:,1],c = Y,s=50, cmap = "rainbow")
    
plt.show()
# fig1.savefig("./name1.png")



在这里插入图片描述
  查看不同核函数在不同数据集上的表现
  注意fig, axes = plt.subplots(nrows, ncols,figsize=(20,16)) 要和画图函数写在一起,如果单独写的话JupyterLab会莫名其妙的把它输入,后面再使用的时候将拿不到子图

nrows=len(datasets)
ncols=len(Kernel) + 1
 
fig, axes = plt.subplots(nrows, ncols,figsize=(20,16))


#第一层循环:在不同的数据集中循环
for ds_cnt, (X,Y) in enumerate(datasets):
    
    #在图像中的第一列,放置原数据的分布 ds_cnt 是行数 , 0 是列数
    ax = axes[ds_cnt, 0] 
    if ds_cnt == 0:
        ax.set_title("Input data")
    ax.scatter(X[:, 0], X[:, 1], c=Y, zorder=10, cmap=plt.cm.Paired,edgecolors='k')
    ax.set_xticks(())
    ax.set_yticks(())
    
    #第二层循环:在不同的核函数中循环
    #从图像的第二列开始,一个个填充分类结果
    for est_idx, kernel in enumerate(Kernel):
        
        #定义子图位置
        ax = axes[ds_cnt, est_idx + 1]
        
        #建模
        clf = svm.SVC(kernel=kernel, gamma=2).fit(X, Y)
        score = clf.score(X, Y)
        
        #绘制图像本身分布的散点图
        ax.scatter(X[:, 0], X[:, 1], c=Y
                   ,zorder=10
                   ,cmap=plt.cm.Paired,edgecolors='k')
        #绘制支持向量
        ax.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=50,
                    facecolors='none', zorder=10, edgecolors='k')# facecolors='none':透明的
        
        #绘制决策边界
        x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
        y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
        
        #np.mgrid,合并了我们之前使用的np.linspace和np.meshgrid的用法
        #一次性使用最大值和最小值来生成网格
        #表示为[起始值:结束值:步长]
        #如果步长是复数,则其整数部分就是起始值和结束值之间创建的点的数量,并且结束值被包含在内
        XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j]
        #np.c_,类似于np.vstack的功能
        Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()]).reshape(XX.shape)
        #填充等高线不同区域的颜色
        ax.pcolormesh(XX, YY, Z > 0, cmap=plt.cm.Paired)
        
        #绘制等高线
        ax.contour(XX, YY, Z, colors=['k', 'k', 'k'], linestyles=['--', '-', '--'],levels=[-1, 0, 1])
        
        #设定坐标轴为不显示
        ax.set_xticks(())
        ax.set_yticks(())
        
        #将标题放在第一行的顶上
        if ds_cnt == 0:
            ax.set_title(kernel)
            
        #为每张图添加分类的分数   
        ax.text(0.95, 0.06, ('%.2f' % score).lstrip('0')
                , size=15
                , bbox=dict(boxstyle='round', alpha=0.8, facecolor='white')
                    #为分数添加一个白色的格子作为底色
                , transform=ax.transAxes #确定文字所对应的坐标轴,就是ax子图的坐标轴本身
                , horizontalalignment='right' #位于坐标轴的什么方向
               )
plt.tight_layout()
plt.show()

在这里插入图片描述
  可以观察到,线性核函数和多项式核函数在非线性数据上表现会浮动,如果数据相对线性可分,则表现不错,如果是像环形数据那样彻底不可分的,则表现糟糕。在线性数据集上,线性核函数和多项式核函数即便有扰动项也可以表现不错,可见多项式核函数是虽然也可以处理非线性情况,但更偏向于线性的功能。
  Sigmoid核函数就比较尴尬了,它在非线性数据上强于两个线性核函数,但效果明显不如rbf,它在线性数据上完全 比不上线性的核函数们,对扰动项的抵抗也比较弱,所以它功能比较弱小,很少被用到。
  rbf,高斯径向基核函数基本在任何数据集上都表现不错,属于比较万能的核函数。我个人的经验是,无论如何先试试看高斯径向基核函数,它适用于核转换到很高的空间的情况,在各种情况下往往效果都很不错,如果rbf效果 不好,那我们再试试看其他的核函数。另外,多项式核函数多被用于图像处理之中。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值