sklearn中SVM的可视化


最近遇到一个简单的二分类任务,本来可用一维的线性分类器来解决,但是为了获得更好的泛化性能,我选取了三个特征,变成了一个三维空间的二分类任务。目的就是使两类样本之间的间隔再大一些,为了满足这种需求,自然而然的想到使用SVM作为分类器,并且该任务是线性可分,自然的选用LinearSVM——核函数为线性函数。为了充分理解SVM,我还对SVM的分类平面、支持向量、bad case均进行可视化,通过本文可以了解:

1 .如何用matplotlib绘制三维散点图
2 .sklearn中SVM的核函数

先看图:

这里写图片描述

其中蓝色的是负样本,红色为正样本,带绿色圈圈的是支持向量,蓝色平面就是分类平面;

再看测试集,其中绿色圈圈,圈出来的是分类错误的样本:
这里写图片描述

第一部分:如何绘制三维散点图和分类平面

这里采用sklearn里面的SVC作为我的分类器,由于分类任务较为简单,几乎是线性可分,所以采用线性核函数,通过以下语句构建SVM并训练:

cls = svm.SVC(kernel='linear', C=1.5)
cls.fit(x_train, y_train)

其中C为惩罚因子,C越大,模型越不能容忍错误,则会使模型更容易过拟合,反之C越小,模型对错误样本容忍性很强,可能导致模型欠拟合。关于系数C的理论可以参考博客,点这里呀

训练好我们的cls之后就是如何绘制分类平面了,这就得知道我们分类平面的表达式是什么。SVM分类平面通式为Wφ(X)+b = 0 ,当采用线性核函数时,分类平面简化为:WX+b=0 (φ(X)=X),其中W,X为向量,b为标量,想进一步了解核函数作用的朋友可以参考博客,点这里呀

本文用例X是一个三维向量,因此W也应该是一个三维的向量,W和b 分别可从cls的coef_ , intercept_这两个属性中获取,具体如下:

w = cls.coef_  
b = cls.intercept_

则绘制分类平面步骤:

	ax = plt.subplot(111, projection='3d')
	x = np.arange(0,1,0.01)
	y = np.arange(0,1,0.11)
	x, y = np.meshgrid(x, y)
	z = (w[0,0]*x + w[0,1]*y + b) / (-w[0,2])
	surf = ax.plot_surface(x, y, z, rstride=1, cstride=1)

首先,创建一个3d的画布,其次要构建分类平面表达式 z = (w[0,0]x + w[0,1]y + b) / (-w[0,2])
其实是这样演变的:
Wφ(X)+b = 0 $ \Rightarrow $ WX+b=0 $ \Rightarrow $ w1
x1+w2
x2+w3*x3 + b = 0

有了分类平面,我们还想知道,支持向量是哪些,那么可以通过cls中的support_ 属性获取支持向量的idx,然后依据idx去训练集中找到我们的支持向量

第二部分:sklearn中的SVM参数介绍

SVM中最关键的就是核函数的选择,上一部分中仅仅采用了最简单的线性核函数(其实等于没用核函数,哈哈哈),SVM中常用的核函数有高斯核(rbf,径向基)、多项式核以及sigmoid核。在这里就简单介绍sklearn中SVM的这些核函数具体使用方法。

1.高斯核(rbf) 表达式:$ K(x,z)=exp(−γ||x−z||^{2})$
涉及参数 γ,默认值为 1/特征维度
创建一个高斯核的SVM分类器:
cls = svm.SVC(kenerl = ‘rbf’,gamma = 0.5 )

2.sigmoid核函数表达式: K ( x , z ) = t a n h ( γ x ∙ z + r ) K(x,z)=tanh(γx∙z+r) K(x,z)=tanhγxz+r)
涉及两个参数:γ,r
γ通过gamma设置,默认值为1/特征维度; r通过coef0设置,默认值为0;
创建一个sigmoid核函数的SVM:
cls = svm.SVC(kenerl = ‘sigmoid’,gamma = 0.3,coef0=0)

3.多项式核表达式: K ( x , z ) = ( γ x ∙ z + r ) d K(x,z)=(γx∙z+r)^{d} K(x,z)=γxz+r)d
涉及三个参数:γ,r,d
γ通过gamma设置,默认值为1/特征维度; r通过coef0设置,默认值为0;,d通过degree设置,默认值为3
创建一个二阶多项式核的SVM:
cls = svm.SVC(kenerl = ‘poly’,gamma = 0.3,coef0=0,dgree=2 )

在SVC中还有一个参数可以控制样本的权重,用以解决unbalance问题,class_weight,具体参考官方文档:
http://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html
推荐博客:
https://www.cnblogs.com/pinard/p/6117515.html

最后留下一个疑问,倘若我采用非线性核,如高斯核函数,我应该如何绘制分类平面?

我的思路是这样的,分类平面表达式:Wφ(X) + b =0, 当采用非线性核的时候,我们如何能知道这个映射函数φ(·)呢?

第三部分:源代码and数据

代码+数据文件可从:
1.CSDN下载:https://download.csdn.net/download/u011995719/10557270
2.百度云: https://pan.baidu.com/s/1s5Xu_h2nlTSum7jeoKniGQ 密码: gtc8

代码:

# coding: utf-8
import numpy as np
import csv
from sklearn import svm
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

"""
采用 sklearn 中的svm 
"""
train_path = './train_set.csv'
test_path = './test_set.csv'

def load_data(data_path):
    X,Y = [],[]
    csv_reader = csv.reader(open(data_path,'r'))
    for row in csv_reader:
        a = row[0][1:-1].split()
        X.append(np.array(a))
        Y.append(np.array(row[1]))
    return X, Y

def find_badcase(X, Y):
    bad_list = []
    y = cls.predict(X)
    for i in range(len(X)):
        if y[i] != Y[i]:
            bad_list.append(i)
    return bad_list

if __name__=="__main__":
    # load data
    x_train, y_train = load_data(train_path)
    x_test, y_test = load_data(test_path)
    # training
    cls = svm.SVC(kernel='linear', C=1.5)
    cls.fit(x_train, y_train)
    # accuracy
    print('Test score: %.4f' % cls.score(x_test, y_test))
    print('Train score: %.4f' % cls.score(x_train, y_train))
    # print bad case id
    bad_idx = find_badcase(x_test,y_test)

    n_Support_vector = cls.n_support_  # 支持向量个数
    sv_idx = cls.support_  # 支持向量索引
    w = cls.coef_  # 方向向量W
    b = cls.intercept_

    # plot
    # 绘制分类平面
    ax = plt.subplot(111, projection='3d')
    x = np.arange(0,1,0.01)
    y = np.arange(0,1,0.11)
    x, y = np.meshgrid(x, y)
    z = (w[0,0]*x + w[0,1]*y + b) / (-w[0,2])
    surf = ax.plot_surface(x, y, z, rstride=1, cstride=1)

    # 绘制三维散点图
    x_array = np.array(x_train, dtype=float)
    y_array = np.array(y_train, dtype=int)
    pos = x_array[np.where(y_array==1)]
    neg = x_array[np.where(y_array==-1)]
    ax.scatter(pos[:,0], pos[:,1], pos[:,2], c='r', label='pos')
    ax.scatter(neg[:,0], neg[:,1], neg[:,2], c='b', label='neg')

    # 绘制支持向量

    X = np.array(x_train,dtype=float)
    for i in range(len(sv_idx)):
        ax.scatter(X[sv_idx[i],0], X[sv_idx[i],1], X[sv_idx[i],2],s=50,
                   c='',marker='o', edgecolors='g')

    # 绘制 bad case
    # x_test = np.array(x_test,dtype=float)
    # for i in range(len(bad_idx)):
    #     j = bad_idx[i]
    #     ax.scatter(x_test[j,0], x_test[j,1], x_test[j,2],s=60,
    #                c='',marker='o', edgecolors='g')

    ax.set_zlabel('Z')    # 坐标轴
    ax.set_ylabel('Y')
    ax.set_xlabel('X')
    ax.set_zlim([0, 1])
    plt.legend(loc='upper left')

    ax.view_init(35,300)
    plt.show()

再次强调:请问如何绘制非线性核的分类平面呢??

  • 18
    点赞
  • 146
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值