2020-05-22 第十三章 支持向量机模型(python)

第十三章 支持向量机模型

01 支持向量机模型的介绍

模型介绍

SVMSupport Vector Machine的简称,它的中文名为支持向量机,属于一种有监督的机器学习算法,可用于离散因变量的分类和连续因变量的预测。通常情况下,该算法相对于其他单一的分类算法(如Logistic回归、决策树、朴素贝叶斯、KNN等)会有更好的预测准确率,主要是因为它可以将低维线性不可分的空间转换为高维的线性可分空间。

image

超平面的理解:在一维空间中,如需将数据切分为两段,只需要一个点即可;在二维空间中,对于线性可分的样本点,将其切分为两类,只需一条直线即可;在三维空间中,将样本点切分开来,就需要一个平面。

距离公式

image

image

SVM的实现思想

image

图中绘制了两条分割直线,利用这两条直线,可以方便地将样本点所属的类别判断出来。虽然从直观上来看这两条分割线都没有问题,但是哪一条直线的分类效果更佳呢(训练样本点的分类效果一致,并不代表测试样本点的分类效果也一样)?甚至于在直线和之间还存在无数多个分割直线,那么在这么多的分割线中是否存在一条最优的“超平面”呢?
image

假设直线是和之间的某条直线(分割面),为了能够寻找到最优的分割面,需要做三件事,首先计算两个类别中的样本点到直线的距离;然后从两组距离中各挑选出一个最短的(如图中所示的距离和),继续比较和,再选出最短的距离(如图中的),并以该距离构造“分割带”(如图中经平移后的两条虚线);最后利用无穷多个分割直线,构造无穷多个“分割带”,并从这些“分割带”中挑选出带宽最大的。

分割带的理解

image

“分割带”代表了模型划分样本点的能力或可信度,“分割带”越宽,说明模型能够将样本点划分得越清晰,进而保证模型泛化能力越强,分类的可信度越高;反之,“分割带”越窄,说明模型的准确率越容易受到异常点的影响,进而理解为模型的预测能力越弱,分类的可信度越低。

SVM的目标函数

image

其中,表示样本点i到某条固定分割面的距离;表示所有样本点与某个分割面之间距离的最小值;表示从所有的分割面中寻找“分割带”最宽的“超平面”;其中w和b代表线性分割面的参数。

02 线性可分的支持向量机

函数间隔的概念

image

将图中五角星所代表的正例样本用表示,将实心圆所代表的负例样本用表示;实体加粗直线表示某条分割面;两条虚线分别表示因变量取值为和时的情况,它们与分割面平行。
不管是五角星代表的样本点,还是实心圆代表的样本点,这些点均落在两条虚线以及虚线之外,则说明这些点带入到方程所得的绝对值一定大于等于。
进而可以说明如果点对应的取值越小于,该样本为负例的可能性越高;点对应的取值越大于,样本为正例的可能性越高。
image

其中,表示样本点所属的类别,用和表示。当计算的值小于等于时,根据分割面可以将样本点对应的预测为;当计算的值大于等于时,分割面会将样本点对应的预测为。故利用如上的乘积公式可以得到线性可分的所对应的函数间隔满足的条件。

几何间隔的概念

image

当分割面中的参数和同比例增加时,所对应的值也会同比例增加,但这样的增加对分割面来说却丝毫没有影响。
所以,为了避免这样的问题,需要对函数间隔做约束,常见的约束为单位化处理。

目标函数

image

目标函数的等价转换

线性可分的SVM所对应的函数间隔满足(γ_i) ̂≥1的条件,故min((γ_i) ̂)就等于1。所以,可以将目标函数J(w,b,i)等价为如下的表达式:

image

由于最大化与最小化是等价的,故可以将上面的表达式重新表示为:
image

拉格朗日乘法

假设存在一个需要最小化的目标函数f(x),并且该目标函数同时受到g(x)≤0的约束。如需得到最优化的解,则需要利用拉格朗日对偶性将原始的最优化问题转换为对偶问题,即:

image

其中,为拉格朗日函数;即为拉格朗日乘子,且。

基于拉格朗日乘法的目标函数

image

目标函数的求解

image

将导函数反代之目标函数:
image

image

其中,表示两个样本点的内积。最终根据已知样本点计算的极小值,并利用拉格朗日乘子的值计算分割面的参数和:
image

简单案例

image

假设样本空间中的三个点可以通过线性可分的SVM进行分类,不妨用实心圆点代表负例、五角星代表正例。如何找到最佳的“超平面”呢?
将样本点带入目标函数
image

将 代入上式
image

对求偏导,并令导函数为
image

经计算可知,,很显然并不满足的条件,目标函数的最小值就需要在边界处获得,即令其中的或,重新计算使达到最小的。
当时,,对求偏导,得到4α_1=0,α_2=2/13,f(α)=−2/13α_2=0f(α)=4α_1^2−2α_1α_1α_1=1/4,α_2=0,f(α)=−1/4f(α)=−1/4α_1=α_3=1/4,α_2=0$。

分割面的求解


image

分割面的表达式


image

03 非线性可分的支持向量机

非线性可分的示意图

image

目标函数

对于非线性SVM模型而言,需要经过两个步骤,一个是将原始空间中的样本点映射到高维的新空间中,另一个是在新空间中寻找一个用于识别各类别样本点线性“超平面”。
假设原始空间中的样本点为x,将样本通过某种转换ϕ(x)映射到高维空间中,则非线性SVM模型的目标函数可以表示为:

image

目标函数的参数求解

其中,内积ϕ( x_i)∙ϕ( x_j)可以利用核函数替换,即K( x_i, x_j)=ϕ( x_i)∙ϕ( x_j)。对于上式而言,同样需要计算最优的拉格朗日乘积α_i,进而可以得到线性“超平面”wb的值:

image

线性核函数

假设原始空间中的两个样本点为( x_i, x_j),在其扩展到高维空间后,它们的内积ϕ( x_i)∙ϕ( x_j)如果等于样本点(x_i, x_j)在原始空间中某个函数的输出,那么该函数就称为核函数。
线性核函数的表达式为K( x_i, x_j)= x_i∙ x_j,故对应的分割“超平面”为:

image

多项式核函数

多项式核函数的表达式为K( x_i, x_j)=(γ( x_i∙ x_j)+r)^p,故对应的分割“超平面”为:

image

其中,和均为多项式核函数的参数。在前面的例子中,核函数实际上就是多项式核函数,其对应的为、为

高斯核函数

高斯核函数的表达式为K( x_i, x_j)=exp(−γ‖ x_i− x_j‖^2),故对应的分割“超平面”为:

image

其中,为高斯核函数的参数,该核函数通常也被称为径向基核函数。

Sigmoid核函数

Sigmoid核函数的表达式为K( x_i, x_j)=tanℎ(γ( x_i∙ x_j)+r),故对应的分割“超平面”为:

image

核函数的选择

在实际应用中,SVM模型对核函数的选择是非常敏感的,所以需要通过先验的领域知识或者交叉验证的方法选出合理的核函数。大多数情况下,选择高斯核函数是一种相对偷懒而有效的方法,因为高斯核是一种指数函数,它的泰勒展开式可以是无穷维的,即相当于把原始样本点映射到高维空间中。

04 支持向量机的应用实战

线性可分函数

LinearSVC(penalty='l2', loss='squared_hinge', dual=True, tol=0.0001, C=1.0, 
          multi_class='ovr', fit_intercept=True, intercept_scaling=1, 
          class_weight=None, verbose=0, random_state=None, max_iter=1000)

penalty:用于指定一范式或二范式的惩罚项,默认为二范式
loss:用于指定某种损失函数,可以是合页损失函数('hinge'),也可以是合页损失函数的平方('squared_hinge'),后者是该参数的默认值
dual:bool类型参数,是否对目标函数做对偶性转换,默认为True,即建模时需要利用拉格朗日函数的对偶性;但样本量超过变量个数时,该参数优先选择False
tol:用于指定SVM模型迭代的收敛条件,默认为0.0001
C:用于指定目标函数中松弛因子的惩罚系数值,默认为1
multi_class:当因变量为多分类问题时,用于指定算法的分类策略。如果为'ovr',表示采用one-vs-rest策略;如果为'crammer_singer',表示联合分类策略,尽管该策略具有更好的准确率,但是其运算过程将花费更多的时间
fit_intercept:bool类型参数,是否拟合线性“超平面”的截距项,默认为True
intercept_scaling:当参数fit_intercept为True时,该参数有效,通过给参数传递一个浮点值,就相当于在自变量X矩阵中添加一常数列,默认该参数值为1
class_weight:用于指定因变量类别的权重,如果为字典,则通过字典的形式{class_label:weight}传递每个类别的权重;如果为字符串'balanced',则每个分类的权重与实际样本中的比例成反比,当各分类存在严重不平衡时,设置为'balanced'会比较好;如果为None,则表示每个分类的权重相等
verbose:bool类型参数,是否输出模型迭代过程的信息,默认为0,表示不输出
random_state:用于指定随机数生成器的种子
max_iter:指定模型求解过程中的最大迭代次数,默认为1000

非线性可分函数

SVC(C=1.0, kernel='rbf', degree=3, gamma='auto', coef0=0.0, shrinking=True, 
        probability=False, tol=0.001, cache_size=200, class_weight=None, 
        verbose=False, max_iter=-1, random_state=None)

C:用于指定目标函数中松弛因子的惩罚系数值,默认为1
kernel:用于指定SVM模型的核函数,该参数如果为'linear',就表示线性核函数;如果为'poly',就表示多项式核函数,核函数中的r和p值分别使用degree参数和gamma参数指定;如果为'rbf',表示径向基核函数,核函数中的r参数值仍然通过gamma参数指定;如果为'sigmoid',表示Sigmoid核函数,核函数中的r参数值需要通过gamma参数指定;如果为'precomputed',表示计算一个核矩阵
degree:用于指定多项式核函数中的p参数值
gamma:用于指定多项式核函数或径向基核函数或Sigmoid核函数中的r参数值
coef0:用于指定多项式核函数或Sigmoid核函数中的r参数值
shrinking:bool类型参数,是否采用启发式收缩方式,默认为True
probability:bool类型参数,是否需要对样本所属类别进行概率计算,默认为False
tol:用于指定SVM模型迭代的收敛条件,默认为0.001
cache_size:用于指定核函数运算的内存空间,默认为200M
class_weight:用于指定因变量类别的权重,如果为字典,则通过字典的形式{class_label:weight}传递每个类别的权重;如果为字符串'balanced',则每个分类的权重与实际样本中的比例成反比,当各分类存在严重不平衡时,设置为'balanced'会比较好;如果为None,则表示每个分类的权重相等
verbose:bool类型参数,是否输出模型迭代过程的信息,默认为0,表示不输出
max_iter:指定模型求解过程中的最大迭代次数,默认为-1,表示不限制迭代次数
random_state:用于指定随机数生成器的种子

手写体字母的识别

# 导入第三方模块
from sklearn import svm
import pandas as pd
from sklearn import model_selection
from sklearn import metrics
# 读取外部数据
letters = pd.read_csv('letterdata.csv')
# 数据前5行
letters.head()
image.png
# 将数据拆分为训练集和测试集
predictors = letters.columns[1:]
X_train,X_test,y_train,y_test = model_selection.train_test_split(letters[predictors], letters.letter, 
                                                                 test_size = 0.25, random_state = 1234)
# 使用网格搜索法,选择线性可分SVM“类”中的最佳C值
C=[0.05,0.1,0.5,1,2,5]
parameters = {'C':C}
grid_linear_svc = model_selection.GridSearchCV(estimator = svm.LinearSVC(),param_grid =parameters,scoring='accuracy',cv=5,verbose =1)
# 模型在训练数据集上的拟合
grid_linear_svc.fit(X_train,y_train)
# 返回交叉验证后的最佳参数值
grid_linear_svc.best_params_, grid_linear_svc.best_score_
Fitting 5 folds for each of 6 candidates, totalling 30 fits

({'C': 0.1}, 0.6914666666666667)
# 模型在测试集上的预测
pred_linear_svc = grid_linear_svc.predict(X_test)
# 模型的预测准确率
metrics.accuracy_score(y_test, pred_linear_svc)
0.7162

经过5重交叉验证后,发现最佳的惩罚系数C为0.1,模型在训练数据集上的平均准确率只有69.2%,同时,其在测试数据集的预测准确率也不足72%,说明线性可分SVM模型并不太适合该数据集的拟合和预测。

# 使用网格搜索法,选择非线性SVM“类”中的最佳C值
kernel=['rbf','linear','poly','sigmoid']
C=[0.1,0.5,1,2,5]
parameters = {'kernel':kernel,'C':C}
grid_svc = model_selection.GridSearchCV(estimator = svm.SVC(),param_grid =parameters,scoring='accuracy',cv=5,verbose =1)
# 模型在训练数据集上的拟合
grid_svc.fit(X_train,y_train)
# 返回交叉验证后的最佳参数值
grid_svc.best_params_, grid_svc.best_score_
Fitting 5 folds for each of 20 candidates, totalling 100 fits


[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 100 out of 100 | elapsed:  9.5min finished

({'C': 5, 'kernel': 'rbf'}, 0.9516666666666665)
# 模型在测试集上的预测
pred_svc = grid_svc.predict(X_test)
# 模型的预测准确率
metrics.accuracy_score(y_test,pred_svc)
0.9596

经过5重交叉验证后,发现最佳的惩罚系数C为5,最佳的核函数为径向基核函数。相比于线性可分SVM模型来说,基于核技术的SVM表现了极佳的效果,模型在训练数据集上的平均准确率高达97.34%,而且其在测试数据集的预测准确率也接近98%,说明利用非线性可分SVM模型拟合及预测手体字母数据集是非常理想的。

# 读取外部数据
forestfires = pd.read_csv('forestfires.csv')
# 数据前5行
forestfires.head()
image.png
# 删除day变量
forestfires.drop('day',axis = 1, inplace = True)
# 将月份作数值化处理
forestfires.month = pd.factorize(forestfires.month)[0]
# 预览数据前5行
forestfires.head()
image
# 导入第三方模块
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.stats import norm
# 绘制森林烧毁面积的直方图
sns.distplot(forestfires.area, bins = 50, kde = True, fit = norm, hist_kws = {'color':'steelblue'}, 
             kde_kws = {'color':'red', 'label':'Kernel Density'}, 
             fit_kws = {'color':'black','label':'Nomal', 'linestyle':'--'})
# 显示图例
plt.legend()
# 显示图形
plt.show()

output_13_0.png


image
# 导入第三方模块
from sklearn import preprocessing
import numpy as np
from sklearn import neighbors
# 对area变量作对数变换
y = np.log1p(forestfires.area)
# 将X变量作标准化处理
predictors = forestfires.columns[:-1]
X = preprocessing.scale(forestfires[predictors])
# 将数据拆分为训练集和测试集
X_train,X_test,y_train,y_test = model_selection.train_test_split(X, y, test_size = 0.25, random_state = 1234)
# 构建默认参数的SVM回归模型
svr = svm.SVR()
# 模型在训练数据集上的拟合
svr.fit(X_train,y_train)
# 模型在测试上的预测
pred_svr = svr.predict(X_test)
# 计算模型的MSE
metrics.mean_squared_error(y_test,pred_svr)
1.9268192310372876
# 使用网格搜索法,选择SVM回归中的最佳C值、epsilon值和gamma值
epsilon = np.arange(0.1,1.5,0.2)
C= np.arange(100,1000,200)
gamma = np.arange(0.001,0.01,0.002)
parameters = {'epsilon':epsilon,'C':C,'gamma':gamma}
grid_svr = model_selection.GridSearchCV(estimator = svm.SVR(),param_grid =parameters,
                                        scoring='neg_mean_squared_error',cv=5,verbose =1, n_jobs=2)
# 模型在训练数据集上的拟合
grid_svr.fit(X_train,y_train)
# 返回交叉验证后的最佳参数值
print(grid_svr.best_params_, grid_svr.best_score_)
Fitting 5 folds for each of 175 candidates, totalling 875 fits


[Parallel(n_jobs=2)]: Using backend LokyBackend with 2 concurrent workers.
[Parallel(n_jobs=2)]: Done 646 tasks      | elapsed:    6.9s


{'C': 300, 'epsilon': 1.1000000000000003, 'gamma': 0.001} -1.994666819631668


[Parallel(n_jobs=2)]: Done 875 out of 875 | elapsed:   10.3s finished
# 模型在测试集上的预测
pred_grid_svr = grid_svr.predict(X_test)
# 计算模型在测试集上的MSE值
metrics.mean_squared_error(y_test,pred_grid_svr)
1.745501223882672
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352