1 SVM基本理论
支持向量机SVM(support vector mac),分类的基本思想是利用最大间隔分类,找到空间中的一个超平面,离这个超平面最近的点叫支持向量,点到超平面的距离叫间隔。如果要处理非线性问题,是通过核函数将特征向量映射到高维空间。从而变成线性可分的。
1.1 几何间隔
我们假设超平面的判别式:
样本到超平面的几何间隔:,表示权重向量,b表示偏移向量,||||表示的内积
1.2 最大化间隔
我们已经知道如何去求数据点到超平面的距离,那么就可以找出支持向量,并计算支持向量的间隔,我们把支持向量x的间隔定义为:
我们可以把这个公式想象为两个平面,,支持向量就在这两个平面上,如果则被分为1类;如果,则被分为-1类。我们现在要做的就是最大化这两个平面的间隔,我们要通过找到最优的w,b来最大化p。
最大化p值的条件限制:,为了计算方便
这种式子通常用拉格朗日来求解:我们的目标变为:
根据凸优化和对偶可以变为:
求导带入得:
用一个正支持向量xs得到b:
1.3 松弛变量
问题似乎已经解决了,但是这里有个假设:数据必须是百分之百可分的。但是实际中的数据几乎都不那么“干净”,或多或少都会存在一些噪点。为此下面我们将引入了松弛变量来解决这种问题,引入松弛变量允许一些数据处于分隔面错误的一侧:
其中的C是用于控制“最大化间隔”和“保证大部分的点的函数间隔都小于1”这两个目标的权重。对上式化解得:
在不可分情况下,对应的KKT条件为:
1.4 核函数
上面的讨论都是在线性可分的情况下,非线性可分的数据SVM通过核函数来求解。核函数是两个向量在隐式映射后的空间中的内积,将数据从输入空间的非线性转变到特征空间,特征空间具有更高甚至无限的维度,从而使得数据在该空间中被转换成线性可分的。核函数有Sigmoid核、线性核、多项式核和高斯核等,其中高斯核和多项式核比较常用,两种核函数均可以把低维数据映射到高维数据。高斯核的公式如下,σ是达到率,即函数值跌落到0的速度参数:
其他常用的核函数的表达式如下表:
2 运行实例
# -*- coding:utf-8 -*-
from sklearn import svm
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import sklearn
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
#define converts(字典)
def Iris_label(s):
it={b'Iris-setosa':0, b'Iris-versicolor':1, b'Iris-virginica':2 }
return it[s]
#读取数据集
path='D:/ML/SVM/Iris.data'
data=np.loadtxt(path, dtype=float, delimiter=',', converters={4:Iris_label} )
#converters={4:Iris_label}中“4”指的是第5列:将第5列的str转化为label(number)
#print(data.shape)
#划分数据与标签
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.7,test_size=0.3) #sklearn.model_selection.
#print(train_data.shape)
#训练svm分类器
classifier=svm.SVC(C=2,kernel='rbf',gamma=20,decision_function_shape='ovr') # ovr:一对多策略
classifier.fit(train_data,train_label.ravel()) #ravel函数在降维时默认是行序优先
'''#计算svc分类器的准确率
print("训练集:",classifier.score(train_data,train_label))
print("测试集:",classifier.score(test_data,test_label))'''
#OR直接调用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)) # (90,3)
print('predict_result:\n',classifier.predict(train_data))'''
#绘制图形
#确定坐标轴范围
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('长度', fontsize=13)
plt.ylabel('宽度', fontsize=13)
plt.xlim(x1_min,x1_max)
plt.ylim(x2_min,x2_max)
plt.title('鸢尾花SVM二特征分类')
plt.show()
fname:文件路径。
dtype:数据类型。float、str等。
delimiter:分隔符。‘,’。
converters:将数据列与转换函数进行映射的字典。eg:{1:fun},含义是将第2列对应转换函数进行转换。
usecols:选取数据的列。
classifier=svm.SVC(C=0.8,kernel='rbf',gamma=20,decision_function_shape='ovr')
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,即将类别两两之间进行划分,用二分类的方法模拟多分类的结果。