【机器学习】python使用支持向量机SVM

准备:    

    数据集

    导入SVM模块

    python 2.7

步骤:

    1.读取数据集

    2.划分训练样本与测试样本

    3.训练SVM分类器

    4.计算分类准确率

    5.绘制图像

 关于SVM的原理知识,在【机器学习】支持向量机中讲过,欲知详情,可戳:

   https://blog.csdn.net/u012679707/article/details/80501358

 在Matlab中可以使用工具箱中的svm算法,具体实例在之前的人脸识别matlab实现中讲过,可戳:

    https://blog.csdn.net/u012679707/article/details/78152713

因为Python中的sklearn库也集成了SVM算法,所以在Python中一样可以使用支持向量机做分类。

【注意】本文的运行环境是windows+Pycharm+python3.6。

Scikit-Learn库基本实现了所有的机器学习算法,具体使用详见官方文档说明:

 http://scikit-learn.org/stable/auto_examples/index.html#support-vector-machines

   因为本文是基于sklearn包,所以需先在python中下载sklearn包,网上有很多教程,在此不再叙述。

数据集

本文用的数据集为Iris.data可从UCI数据库中下载,http://archive.ics.uci.edu/ml/datasets/Iris

 Iris.data的数据格式如下:共5列,前4列为样本特征,第5列为类别,分别有三种类别Iris-setosa, Iris-versicolor, Iris-virginica。

 注意:因为在分类中类别标签必须为数字量,所以应将Iris.data中的第5列的类别(字符串)转换为num.

导入SVM模块

首先在使用SVM时,需先从sklearn包中导入SVM模块。

from sklearn import svm

1.读取数据集

#1.读取数据集
path='F:/Python_Project/SVM/data/Iris.data'
data=np.loadtxt(path, dtype=float, delimiter=',', converters={4:Iris_label} )
#converters={4:Iris_label}中“4”指的是第5列:将第5列的str转化为label(number)

定义的转换函数为:可实现将类别Iris-setosa, Iris-versicolor, Iris-virginica映射成 0,1,2。

#define converts(字典)
def Iris_label(s):
    it={b'Iris-setosa':0, b'Iris-versicolor':1, b'Iris-virginica':2 }
    return it[s]

读取文件用的是loadtxt函数,其声明如下:

def  loadtxt(fname, dtype=float, comments='#', delimiter=None,converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)

常用的参数有:

        fname: 文件路径,例 path='F:/Python_Project/SVM/data/Iris.data'

dtype:样本的数据类型 例dtype=float

delimiter:分隔符。例 delimiter=','

converters:将数据列与转换函数进行映射字典。例 converters={4:Iris_label}含义是将第5列的数据对应转换函数进行转换。

usecols:选取数据的列。

2.划分训练样本与测试样本

#2.划分数据与标签
x,y=np.split(data,indices_or_sections=(4,),axis=1) #x为数据,y为标签
x=x[:,0:2] #为便于后边画图显示,只选取前两维度。若不用画图,可选取前四列x[:,0:4]
train_data,test_data,train_label,test_label =sklearn.model_selection.train_test_split(x,y, random_state=1, train_size=0.6,test_size=0.4)

 1. split(数据,分割位置,轴=1(水平分割) or 0(垂直分割))。
  2.  sklearn.model_selection.train_test_split随机划分训练集与测试集。train_test_split(train_data,train_label,test_size=数字, random_state=0)

  参数解释:

      train_data:所要划分的样本特征集

      train_label:所要划分的样本类别

      test_size:样本占比,如果是整数的话就是样本的数量.(注意:)

                   --  test_size:测试样本占比。 默认情况下,该值设置为0.25。 默认值将在版本0.21中更改。 只有train_size没有指定时, 

                        它将保持0.25,否则它将补充指定的train_size,例如train_size=0.6,则test_size默认为0.4。

                   -- train_size:训练样本占比。

      random_state:是随机数的种子。

随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数。

3.训练SVM分类器

#3.训练svm分类器
classifier=svm.SVC(C=2,kernel='rbf',gamma=10,decision_function_shape='ovr') # ovr:一对多策略
classifier.fit(train_data,train_label.ravel()) #ravel函数在降维时默认是行序优先

     kernel='linear'时,为线性核,C越大分类效果越好,但有可能会过拟合(defaul C=1)。

  kernel='rbf'时(default),为高斯核,gamma值越小,分类界面越连续;gamma值越大,分类界面越“散”,分类效果越好,但有可能会过拟合。

  decision_function_shape='ovr'时,为one v rest(一对多),即一个类别与其他类别进行划分,

  decision_function_shape='ovo'时,为one v one(一对一),即将类别两两之间进行划分,用二分类的方法模拟多分类的结果。

4.计算分类准确率

#4.计算svc分类器的准确率
print("训练集:",classifier.score(train_data,train_label))
print("测试集:",classifier.score(test_data,test_label))

结果:

        

还有另一种计算准确率的方法:

#也可直接调用accuracy_score方法计算准确率
from sklearn.metrics import accuracy_score
tra_label=classifier.predict(train_data) #训练集的预测标签
tes_label=classifier.predict(test_data) #测试集的预测标签
print("训练集:", accuracy_score(train_label,tra_label) )
print("测试集:", accuracy_score(test_label,tes_label) )

实际上,classifier.score()内部也是先predict得到tes_label , 然后调用了accuracy_score(test_label,tes_label)方法来计算准确率的。

可以查看一下内部决策函数,返回的是样本到分类超平面的距离

#查看决策函数
print('train_decision_function:',classifier.decision_function(train_data)) # (90,3)
print('predict_result:',classifier.predict(train_data))

(1) 若选用“ovr”(一对多),则每个样本会产生3个距离值(3为类别种类数)。如下

 

(2)若选用“ovo”(一对一),则每个样本会产生3*(3-1)/2=3 个距离值,即 :距离值个数=类别数*(类别数-1)/2。结果如下:

    

5.绘制图像

确定坐标轴范围、字体、背景颜色

#5.绘制图形
#确定坐标轴范围
x1_min, x1_max=x[:,0].min(), x[:,0].max() #第0维特征的范围
x2_min, x2_max=x[:,1].min(), x[:,1].max() #第1维特征的范围
x1,x2=np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j ] #生成网络采样点
grid_test=np.stack((x1.flat,x2.flat) ,axis=1) #测试点
#指定默认字体
matplotlib.rcParams['font.sans-serif']=['SimHei']
#设置颜色
cm_light=matplotlib.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
cm_dark=matplotlib.colors.ListedColormap(['g','r','b'] )
 
grid_hat = classifier.predict(grid_test)       # 预测分类值
grid_hat = grid_hat.reshape(x1.shape)  # 使之与输入的形状相同

这里用到了mgrid()函数,该函数的作用这里简单介绍一下:

   假设假设目标函数F(x,y)=x+y。x轴范围1~3,y轴范围4~6,当绘制图像时主要分四步进行:

【step1:x扩展】(朝右扩展):

       [1 1 1]

   [2 2 2]

   [3 3 3]

【step2:y扩展】(朝下扩展):

   [4 5 6]

   [4 5 6]

   [4 5 6]

【step3:定位(xi,yi)】:

   [(1,4) (1,5) (1,6)]

   [(2,4) (2,5) (2,6)]

   [(3,4) (3,5) (3,6)]

【step4:将(xi,yi)代入F(x,y)=x+y】

 因此这里x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]后的结果为:

 

再通过stack()函数,axis=1,生成测试点

绘图:

plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)     # 预测值的显示
plt.scatter(x[:, 0], x[:, 1], c=y[:,0], s=30,cmap=cm_dark)  # 样本
plt.scatter(test_data[:,0],test_data[:,1], c=test_label[:,0],s=30,edgecolors='k', zorder=2,cmap=cm_dark) #圈中测试集样本点
plt.xlabel('花萼长度', fontsize=13)
plt.ylabel('花萼宽度', fontsize=13)
plt.xlim(x1_min,x1_max)
plt.ylim(x2_min,x2_max)
plt.title('鸢尾花SVM二特征分类')
plt.show()

 pcolormesh(x,y,z,cmap)这里参数代入x1,x2,grid_hat,cmap=cm_light绘制的是背景。
 scatter中edgecolors是指描绘点的边缘色彩,s指描绘点的大小,cmap指点的颜色。

 xlim指图的边界。

 pcolormesh(x,y,z,cmap)绘制的背景如下:即将坐标系下的点都进行一个分类。

plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)     # 预测值的显示

所有样本点的分类结果:

将测试点从中圈出来:

完整代码如下:

# -*- coding:utf-8 -*-
import matplotlib.pyplot as plt
from sklearn import svm
import numpy as np
import matplotlib
import sklearn
from sklearn.model_selection import train_test_split
import pandas as pd

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

#define converts(字典)
def Iris_label(s):
    it = {b'Iris-setosa':0,b'Iris-versicolor':1,b'Iris-virginica':2}
    return it[s]

#1.读取数据集
path = u'iris/iris.data'  # 数据文件路径
data = np.loadtxt(path,dtype=float,delimiter=',',converters={4:Iris_label})
#converters={4:Iris_label}中“4”指的是第5列:将第五列的str转化为label(number)
#print(data.shape)

#2.划分数据与标签
x,y = np.split(data,indices_or_sections=(4,),axis=1) #x为数据,y为标签
x=x[:,0:2]
train_data,test_data,train_label,test_label = train_test_split(x,y,random_state=1,train_size=0.6,test_size=0.4) #sklearn.model_selection.
# print(train_data.shape)

#3.训练svm分类器
classifier = svm.SVC(C=2,kernel='rbf',gamma=10,decision_function_shape='ovo')#一对多
classifier.fit(train_data,train_label.ravel())#ravel函数在降维时默认是行序优先

#4.计算svc分类器的准确率
print("训练集:",classifier.score(train_data,train_label))
print("测试集:",classifier.score(test_data,test_label))

#也可直接调用accuracy_score方法计算准确率
from sklearn.metrics import accuracy_score
tra_label = classifier.predict(train_data)#训练集的预测标签
tes_label = classifier.predict(test_data)#测试集的预测标签
print("训练集:",accuracy_score(train_label,tra_label))
print("测试集:",accuracy_score(test_label,tes_label))

#查看决策函数
print('train_decision_function:\n',classifier.decision_function(train_data))
print('predict_result:\n',classifier.predict(train_data))

#5.绘制图形
#确定坐标轴范围
x1_min,x1_max = x[:,0].min(),x[:,0].max() #第0维特征的范围
x2_min,x2_max=x[:,1].min(),x[:,1].max() #第1维特征的范围
x1,x2 = np.mgrid[x1_min:x1_max:200j,x2_min:x2_max:200j] #生成网络采样点
grid_test=np.stack((x1.flat,x2.flat),axis=1) #测试点
#指定默认字体
matplotlib.rcParams['font.sans-serif']=['SimHei']
#设置颜色
cm_light=matplotlib.colors.ListedColormap(['#A0FFA0','#FFA0A0','#A0A0FF'])
cm_dark = matplotlib.colors.ListedColormap(['g','r','b'])

grid_hat = classifier.predict(grid_test) #预测分类值
grid_hat = grid_hat.reshape(x1.shape) #使之与输入的形状相同

plt.pcolormesh(x1,x2,grid_hat,cmap=cm_light) #预测值得显示
plt.scatter(x[:,0],x[:,1],c=y[:,0],s=30,cmap=cm_dark) #样本
plt.scatter(test_data[:,0],test_data[:,1],c=test_label[:,0],s=30,edgecolors='k',zorder=2,cmap=cm_dark) #圈中测试集样本点
plt.xlabel(u"花萼长度",fontsize=13)
plt.ylabel(u"花萼宽度",fontsize=13)
plt.xlim(x1_min,x1_max)
plt.ylim(x2_min,x2_max)
plt.title(u"鸢尾花SVM二特征分类")
plt.show()

猜你喜欢

转载自blog.csdn.net/rocling/article/details/89473718