1、支持向量机SVM
对两类样本点进行分类,如下图,有a线、b线、c线三条线都可以将两类样本点很好的分开类,我们可以观察到b线将两类样本点分类最好,原因是我们训练出来的分类模型主要应用到未知样本中,虽然a、b、c三条线将训练集都很好的分开类,但是当三个模型应用到新样本中时,b线抗干扰能力最强,也就是泛化能力最好,样本变化一些关系不大,一样能被正确的分类。那么如何确定b线的位置呢?我们可以使用支持向量机SVM来确定b线的位置。

支持向量机(support vector machines,SVM)是一种二分类算法,它的目的是寻找一个超平面来对样本进行分割,分割的原则是间隔最大化,如果对应的样本特征少,一个普通的SVM就是一条线将样本分隔开,但是要求线到两个类别最近样本点的距离要最大。

如上图所示,b线就是我们根据支持向量机要找到的分割线,这条线需要到两个类别最近的样本点最远,图上的距离就是d,由于这条线处于两个类别的中间,所以到两个类别的距离都是d。
支持向量机SVM算法就是在寻找一个最优的决策边界(上图中的两条虚线)来确定分类线b,所说的支持向量(support vector)就是距离决策边界最近的点(上图中p1、p2、p3点,只不过边界穿过了这些点)。如果没有这些支持向量点,b线的位置就要改变,所以 SVM就是根据这些支持向量点来最大化margin,来找到了最优的分类线(machine,分类器) ,这也是SVM分类算法名称的由来。
2、构建SVM目标函数
接着上面的分类问题来分析,假设支持向量机最终要找的线是

【知识补充】:
- 二维空间点
到直线 的距离公式是:
- 两条平行线
与 之间的距离公式为:
我们希望的是决策边界上的样本点到
以上
由于
我们可以看到无论计算点到直线的距离还是两个平行线之间的距离,最终结果是一致的。对于

那么变换之后的d可以根据两条平行线之间的距离得到:
我们希望决策边界上的点到超平面
两式两侧分别乘以对应的类别可以合并为一个式子:
所以在计算d的最大值时,是有限制条件的,这个限制条件就是(3)式。
所以对于所有样本点我们需要在满足
以上n代表样本总数,缩写
3、拉格朗日乘子法
3.1、拉格朗日乘子法
拉格朗日乘数法主要是将有等式约束条件优化问题转换为无约束优化问题 ,拉格朗日乘数法如下:
假设
可以引入一个自变量
以上就是拉格朗日乘数法,通俗理解拉格朗日乘数法就是将含有等式条件约束优化问题转换成了无约束优化问题构造出拉格朗日函数
拉格朗日函数转换成等式过程的证明涉及到导数积分等数学知识,这里不再证明。
参考文章:
3.2、KKT条件
假设我们面对的是不等式条件约束优化问题,如下:
假设
针对上式,显然是一个不等式约束最优化问题,不能再使用拉格朗日乘数法,因为拉格朗日乘数法是针对等式约束最优化问题。
那我们可以考虑加入一个“松弛变量”
以上②式变成了等式条件约束优化问题,我们就可以使用拉格朗日乘数法来求解满足等式条件下
通过拉格朗日乘数法,将②式转换为如下:
但是上式中
所以将上式转换成如下拉格朗日函数:
以上我们可以看到将不等式条件约束优化问题加入“松弛变量”转换成等式条件约束优化问题,使用拉格朗日乘数法进行转换得到
从上式⑥式可知
由于
由于
综上两个步骤我们可以得到:
约束条件起作用时,
约束条件不起作用时,
上面方程组 $ g$ 可以进行如下化简:
以上便是不等式约束优化问题的KKT(Karush-Kuhn-Tucker)条件 。
我们回到最开始要处理的问题上,根据③式可知,我们需要找到合适的
我们对③式的优化问题可以进行优化如下:
由于
满足最小化⑧式对应的
假设现在我们找到了合适的参数
也就是说一定有:
为了找到最优的
公式⑨可以这么描述:最小化关于 x 的最大化关于 λ 的 L(x, λ) 函数。
参考文章:KKT不等式约束
解方程可得:
其中的
3.3、对偶问题
原问题
对原问题的约束条件整合【带KKT条件的拉格朗日函数】
这个公式的理解:
最小化关于 x 的最大化关于 λ 的 L(x, λ) 函数,并满足 λ
我们可以使用拉格朗日乘子法将这个问题转化为带有等式约束的拉格朗日函数,并使用 KKT 条件来求解最优解。但是,这个问题的求解往往非常复杂,尤其是当数据集非常大时,计算复杂度将非常高。
通过对原问题进行对偶转换,我们可以将原问题转化为一个只涉及内积的问题,从而减少计算复杂度。具体来说,我们将原问题中的变量
我们将原问题转换一下,其实就是把min和max对调了一下(可以理解为从不同的方向,进行求解):
式⑩称为原问题的对偶问题(对上面方程式⑨的求解等效求解式⑩)。
这个公式的理解:
最大化关于 λ 的最小化关于 x 的L(x, λ) 函数,并满足 λ
在许多情况下,原问题和对偶问题的解是相同的,因此,求解了式⑩对偶问题的解,即是解出了原问题式⑨的解。
但是原问题跟对偶问题并不完全是等价的,这里有一个强对偶性、弱对偶性的概念,弱对偶性是对于所有的对偶问题都有的一个性质。
这里给出一个弱对偶性的推导过程:
其中
如果两个问题是强对偶的,那么这两个问题其实是等价的问题:
所有的下凸函数都满足强对偶性,SVM的目标函数即原问题是一个下凸二次规划问题,所以SVM原问题和其对偶问题是满足强对偶性,即两个问题是等价的。
【备注】:对弱对偶性推导的理解如下图所示:

4、目标函数优化【硬间隔】
通过2小节【构建SVM目标函数】我们知道SVM目标函数如下:
根据拉格朗日乘数法、KKT条件、对偶问题我们可以按照如下步骤来计算SVM目标函数最优的一组w值。
4.1、构造拉格朗日函数
将SVM目标函数转换为如下:
根据3.2【KKT条件】中的⑨式构建拉格朗日函数如下:
以上不等式转换成拉格朗日函数必须满足KKT条件,详见3.2【KKT条件】,这里满足的KKT条件如下:
4.2、对偶转换
由于原始目标函数
针对b式,我们假设参数
进一步可以得到:
按照解方程组的思想,我们现在将以上计算得到的结果代入到b式中得到:
即:
我们可以发现以上公式经过转换只含有
注意:d式中
4.3、SMO算法求解(了解)
SMO(Sequential Minimal Optimization),序列最小优化算法,其核心思想非常简单:每次只优化一个参数,其他参数先固定住,仅求当前这个优化参数的极值。下面我们只说SVM中如何利用SMO算法进行求解最终结果的,这里不再进行公式推导。
我们根据d式可以看到有
根据SMO算法假设将
我们可以将上式中c看成是
然后对其他的
4.4、计算分割线w和b的值
根据4.2中的c式,如下:
我们可以知道获取了一组
根据f式中式可知,当
一定可以计算出b的值。我们将g式两边乘以
由于
假设我们有S个支持向量,以上b的计算可以使用任意一个支持向量代入计算即可,如果数据严格是线性可分的,这些b结果是一致的。对于数据不是严格线性可分的情况,参照后面的软间隔问题,一般我们可以采用一种更健壮的方式,将所有支持向量对应的b都求出,然后将其平均值作为最后的结果,最终b的结果如下:
S代表支持向量点的集合,也就是在边界上点的集合。
综上所述,我们可以的到最终的w和b的值如下:
确定w和b之后,我们就能构造出最大分割超平面:
5、软间隔及优化
5.1、软间隔问题
以上讨论问题都是基于样本点完全的线性可分,我们称为硬间隔如下图:

如果存在部分样本点不能完全线性可分,大部分样本点线性可分的情况,如下图所示:

那么我们就需要用到软间隔,相比于硬间隔的苛刻条件,我们允许个别样本点出现在间隔带里面,比如:

即我们允许部分样本点不满足约束条件:
为了度量这个间隔软到何种程度,我们为每个样本引入一个“ 松弛变量 ”

内部点:
边界点:
正确误差点:
错误误差点:
5.2、优化SVM目标函数(了解)
加入软间隔后我们的目标函数变成了:
其中C是一个大于0的常数,这里在原有的目标函数中加入
接下来我们对新的目标函数h式求解最优化问题,步骤与 4、最小化SVM目标函数【硬间隔】完全线性可分步骤完全一样。
- 构造拉格朗日函数
将h式目标函数改写成如下:
构造拉格朗日函数如下:
上式中
- 对偶关系转换
目标函数是个下凸函数,对应的拉格朗日函数复合强对偶性,所以可以根据强对偶向,将对偶问题转换为:
即:
使用j式对
整理之后得到:
将以上关系代入到 j 式:
我们发现上式中求
推导到以上之后,我们发现结果和硬间隔结果一样,参照4.3 d式,只是结果中多了约束条件
3.求解结果
同样我们也可以利用SMO算法对式L求解得到一组合适的
这里得到的w和b虽然和硬分割结果一样,但是这是加入松弛变量之后得到的w和b的值,根据L式的条件
那么确定w和b之后,我们就能构造出最大分割超平面:
5.3、SVM代码演练
二维超平面案例演示
- 构造数据
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVC # 分类算法
from sklearn import datasets
X,y = datasets.make_blobs(n_samples=100,# 样本量
n_features=2,# 二维数据,便于画图展示
centers=2,# 两类
random_state=3)# 随机数状态,固定了
display(X.shape,y.shape,np.unique(y))
plt.scatter(X[:,0],X[:,1],c=y)
plt.show()- 建模
# kernel 表示核函数:linear,线性
svc = SVC(kernel = 'linear')
svc.fit(X,y)
display(svc.score(X,y))
# 获取斜率和截距
w_ = svc.coef_# 特征两个
b_ = svc.intercept_
display(w_,b_)- 绘制分离超平面
符号,使用什么表示,无影响
得到y关于x的方程
边界线的计算,算的就是截距
w = - w_[0,0]/w_[0,1]
b, = - b_/w_[0,1]
sv = svc.support_vectors_
x = np.linspace(-5,1,100)
y_result = w * x + b
plt.scatter(X[:,0],X[:,1],c = y)
plt.plot(x,y_result,color = 'red')
# 上边界和下边界
b1 = sv[0][1] - w * sv[0][0]
plt.plot(x, w * x + b1 ,color = 'blue',ls = '--')
b2 = sv[-1][1] - w * sv[-1][0]
plt.plot(x, w * x + b2, color = 'blue', ls = '--')以乳腺癌为例,使用SVM进行建模训练
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
X,y = datasets.load_breast_cancer(return_X_y=True)
display(X.shape,y.shape)
svc = SVC(kernel='linear')
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=42)
svc.fit(X_train,y_train)
svc.score(X_test,y_test)
%%time
model = SVC(kernel='linear')
scores = 0
for i in range(100):
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2)
model.fit(X_train,y_train)
score = model.score(X_test,y_test)
scores += score/100
print('100次随机拆分,SVC算法的平均得分是:',scores)5.4、网格搜索最佳参数

网格搜索就是手动给定模型中想要改动的所有参数,程序自动使用穷举法来将所有的参数或者参数组合都运行一遍,将对应得到的模型做K折交叉验证,将得分最高的参数或参数组合当做最佳结果,并得到模型。

也就是说网格搜索用来获取最合适的一组参数,不需要我们手动一个个尝试。使用网格搜索由于针对每个参数下的模型需要做K折交叉验证最终导致加大了模型训练时间,所以一般我们可以在小的训练集中使用网格搜索找到对应合适的参数值,再将合适的参数使用到大量数据集中训练模型。例如:逻辑回归中使用正则项时,我们可以先用一小部分训练集确定合适的惩罚系数,然后将惩罚系数应用到大量训练集中训练模型。
SVC超参数介绍:
- 核函数(kernel): 常用的核函数有线性(linear)、多项式(poly)、径向基函数(Radial basis function,RBF)和sigmoid。核函数的选择将影响模型在特征空间中的映射方式。
- 惩罚参数(C): C是一个正则化参数,用于控制模型的复杂度。较小的C值会导致较大的间隔,但可能允许一些误分类。较大的C值会产生较小的间隔,试图最小化训练错误,但可能导致过拟合。
- gamma(γ): gamma仅在使用RBF、poly或sigmoid核时需要设置。它控制了单个训练样本的影响范围。较大的gamma值会导致更复杂的决策边界,而较小的gamma值会产生更简单的边界。
from sklearn.svm import SVC
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
import pandas as pd
X,y = datasets.load_breast_cancer(return_X_y=True)
score = 0
search_space = {'C': np.logspace(-3, 3, 7)}
best_params = []
for i in range(100):
X_train,X_test,y_train,y_test = train_test_split(X,y)
model = SVC()
gc = GridSearchCV(model, param_grid=search_space,cv=5)
gc.fit(X_train,y_train)
best_params.append(gc.best_params_['C'])
best_model = gc.best_estimator_
best_model.fit(X_train,y_train)
score += best_model.score(X_test,y_test)
print('模型平均得分是:',score)
# 查看最佳参数
pd.value_counts(best_params)5.5、SVM立体原理可视化
- 构造数据
import numpy as np
from sklearn.svm import SVC
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
rs = np.random.RandomState(256) # 种子,生成随机数字,固定了
X = rs.randn(300,2)
# y目标值,一三象限是1,二四象限是0
y = [1 if i > 0 else 0 for i in X[:,0] * X[:,1]]
plt.figure(figsize=(6,6))
plt.scatter(X[:,0],X[:,1],c = y)- 建模
svc = SVC(kernel='rbf')
# 规律,一三象限是一个类别,二四象限是另一个类别
svc.fit(X,y)- 预测
X1 = np.linspace(-3,3,200)
X2 = np.linspace(-3,3,180)
X1,X2 = np.meshgrid(X1,X2)
# 测试数据,36000个测试点,密密麻麻
X_test = np.column_stack([X1.ravel(),X2.ravel()])
plt.scatter(X_test[:,0],X_test[:,1])- 可视化
# SVC对数据划分,直线划分两类
# 高维,超平面
# 不同点,距离超平面不同!
d = svc.decision_function(X_test)# 36000个距离
print(d.max(),d.min())- 轮廓线
# 轮廓线
plt.figure(figsize=(6,6))
plt.contour(X1,X2,d.reshape(180,200))- 轮廓面
# 轮廓面
plt.figure(figsize=(6,6))
plt.contourf(X1,X2,d.reshape(180,200))- 3D距离可视化
plt.figure(figsize=(12,9))
ax = plt.subplot(111,projection = '3d')
ax.contourf(X1,X2,d.reshape(180,200))
ax.view_init(50,-60)5.6、超参数筛选案例
- 加载数据
import numpy as np
from sklearn.svm import SVC
def read_data(path):
with open(path) as f :
lines=f.readlines()
lines=[eval(line.strip()) for line in lines]
X,y=zip(*lines)
X=np.array(X)
y=np.array(y)
return X,y
X_train,y_train = read_data('./data/train_data')
display(X_train.shape)
X_test,y_test = read_data('./data/test_data')
display(X_test.shape)- 建模预测
svc = SVC(kernel='sigmoid')
svc.fit(X_train,y_train.ravel())
svc.score(X_test,y_test.ravel())- 超参数筛选
%%time
svc = SVC(kernel='sigmoid')
# 不同C,效果不同啊:0.1,0.5,1,10……
params = {'C':np.logspace(-3,3,50),'tol':[0.0001,0.001,0.01,0.1,1]}
gc = GridSearchCV(estimator = svc,param_grid = params,cv = 5)
gc.fit(X_train,y_train.ravel())
print('最优超参数:',gc.best_params_)
best_model = gc.best_estimator_
best_model.fit(X_train,y_train)
best_model.score(X_test,y_test.ravel())6、SVM Hinge Loss【了解】
软间隔情况下,SVM的目标函数如下:
其实这里我们说SVM的损失主要说的就是上式中的松弛变量
根据h式的条件$ 1-y(w^T\cdot x_i +b) - \xi_i \le 0,\xi_i \ge 0$我们可以改写成如下:
根据下图结合以上两个条件我们可以继续改写成如下:

上式等价于:
以上公式就是SVM的损失函数,称为“Hinge Loss”,也被叫做“合页损失函数”。其图像如下:

特点是当
我们可以将m式代入到h式得到新的目标函数,暂时先不关注约束条件,新的目标函数如下:
针对新的目标函数我们同样也是最小化整体目标函数。我们发现以上目标函数与逻辑回归L2正则化的损失函数在形式上非常类似,将上式可以改写成如下:
逻辑回归L2正则化损失函数如下:
也可以改写成如下:
如果将逻辑损失函数图像与“Hinge Loss”图像放在一起图像如下:

通过上图我们可以看出,在训练逻辑回归时,损失永远不为0,因此即使分类正确,逻辑回归仍然会不停的训练,以求得更小的损失和更大的概率,但是极有可能出现过拟合,这就是为什么我们需要在梯度下降中提前终止的原因。但是在SVM中,如果分类正确可以直接达到
7、核函数
7.1、非线性核函数
在前面SVM讨论的硬间隔和软间隔都是指的样本完全可分或者大部分样本点线性可分的情况。那么如果样本完全线性不可分如下图所示:

我们可以使用升维方式来解决这种线性不可分的问题,例如目前只有两个维度

SVM中线性不可分问题就是非线性SVM问题,对这种问题我们可以将样本映射到高维空间,再通过间隔最大化的方式学习得到支持向量机。
7.2、核函数(kernel function)
假设原有特征有如下三个
我们在训练模型时将以上组合特征可以参与到模型的训练中,其代价是运算量过大,比如原始特征有m个,那么二阶交叉的维度为
有两个向量
之后计算两者内积如下:
另外我们计算m和n的内积如下:
对结果进行平方得到:
【备注】:
我们发现o式和p式结果一样,也就是
以上在m和n向量中只有3个元素时推导成立,那么在m和n中如果有多个元素时也一样成立。
我们发现,如果最终目标只是计算向量升维后的内积
以上核函数叫做多项式核函数,常用的核函数有如下几种,不同的核函数的区别是将向量映射到高维空间时采用的升维方法不同,不过高维向量都是不需要计算出来的。
- 线性核函数:
- 多项式核函数:
- 高斯核函数:
7.3、核函数在SVM中应用
在非线性SVM中,我们可以对原始特征进行升维,原有的超平面
可知最终经过对偶处理后的目标函数如下:
以上公式与l式不同的是只是将
这样我们可以通过核函数将数据映射到高维空间,但是核函数是在低维上进行计算,而将实质上的分类效果表现在了高维空间上,来解决在原始空间中线性不可分的问题。
在SVM中我们可以使用常用的核函数:线性核函数、多项式核函数、高斯核函数来进行升维解决线性不可分问题,应用最广泛的就是高斯核函数,无论是小样本还是大样本、高维或者低维,高斯核函数均适用,它相比于线性核函数来说,线性核函数只是高斯核函数的一个特例,线性核函数适用于数据本身线性可分,通过线性核函数来达到更理想情况。高斯核函数相比于多项式核函数,多项式核函数阶数比较高时,内部计算时会导致一些元素值无穷大或者无穷小,而在高斯核函数会减少数值的计算困难。
综上,我们在非线性SVM中使用核函数时,先使用线性核函数,如果不行尝试换不同的特征,如果还不行那么可以直接使用高斯核函数。
非线性SVM使用核函数代码如下:
from sklearn import svm
from sklearn import datasets
from sklearn.model_selection import train_test_split as ts
X,y = datasets.load_wine(return_X_y=True)
#split the data to 7:3
X_train,X_test,y_train,y_test = ts(X,y,test_size=0.3)
print(y_test)
# select different type of kernel function and compare the score
# kernel = 'rbf'
clf_rbf = svm.SVC(kernel='rbf')
clf_rbf.fit(X_train,y_train)
score_rbf = clf_rbf.score(X_test,y_test)
print("The score of rbf is : %f"%score_rbf)
# kernel = 'linear'
clf_linear = svm.SVC(kernel='linear')
clf_linear.fit(X_train,y_train)
score_linear = clf_linear.score(X_test,y_test)
print("The score of linear is : %f"%score_linear)
# kernel = 'poly'
clf_poly = svm.SVC(kernel='poly')
clf_poly.fit(X_train,y_train)
score_poly = clf_poly.score(X_test,y_test)
print("The score of poly is : %f"%score_poly)7.4、非线性核函数
- 数据构建
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
X,y = datasets.make_circles(n_samples=100,factor=0.7)
X += np.random.randn(100,2)*0.03
display(X.shape,y.shape)
plt.figure(figsize=(5,5))
cmap = ListedColormap(colors = ['blue','red'])
plt.scatter(X[:,0],X[:,1],c = y,cmap = cmap)- 建模预测核函数对比
svc = SVC(kernel='linear')
svc.fit(X,y)
print('线性核函数:',svc.score(X,y))
svc = SVC(kernel='rbf')
svc.fit(X,y)
print('高斯核函数:',svc.score(X,y))
svc = SVC(kernel='poly',degree = 2)
svc.fit(X,y)
print('高斯核函数:',svc.score(X,y))7.5、支持向量机回归问题
- 数据构建
import numpy as np
from sklearn.svm import SVR
import matplotlib.pyplot as plt
X = np.linspace(0,2*np.pi*2,100).reshape(-1,1)
y = np.sin(X)
plt.scatter(X,y)- 不同核函数建模对比
# 线性核函数
svr = SVR(kernel='linear')
svr.fit(X,y.ravel())
y_ = svr.predict(X)
plt.scatter(X,y)
# 绘制预测结果
plt.plot(X,y_,color = 'red')# 高斯核函数
svr = SVR(kernel='rbf')
svr.fit(X,y.ravel())
y_ = svr.predict(X)
plt.scatter(X,y)
# 绘制预测结果
plt.plot(X,y_,color = 'red')# 多项式核函数
svr = SVR(kernel='poly',degree=2)
svr.fit(X,y.ravel())
y_ = svr.predict(X)
plt.scatter(X,y)
# 绘制预测结果
plt.plot(X,y_,color = 'red')7.6、SVM-天猫双十一销量预测
- 数据构造
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVR
X = np.arange(2009,2020) - 2008
y = np.array([0.5,9.36,52,191,350,571,912,1207,1682,2135,2684])
plt.scatter(X,y,color = 'red')
# 划分份数多,画图,曲线平滑
X_test = np.linspace(2009,2019,100).reshape(-1,1) - 2008- 建模拟合
# 线性核函数
svr = SVR(kernel = 'linear')
svr.fit(X.reshape(-1,1),y)
y_ = svr.predict(X_test)
plt.scatter(X,y,color = 'red')
plt.plot(X_test.ravel(),y_,color = 'green')
svr.coef_# 高斯核函数
svr = SVR(kernel = 'rbf')
svr.fit(X.reshape(-1,1),y)
y_ = svr.predict(X_test)
plt.scatter(X,y,color = 'red')
plt.plot(X_test.ravel(),y_,color = 'green')# 多项式核函数
svr = SVR(kernel = 'poly',coef0=20,degree = 3)
svr.fit(X.reshape(-1,1),y)
y_ = svr.predict(X_test)
plt.scatter(X,y,color = 'red')
plt.plot(X_test.ravel(),y_,color = 'green')8、支持向量机SVM特点
8.1、抗干扰能力强
根据一些样本点,我们可以通过拉格朗日乘数法、KKT条件、对偶问题、SMO算法计算出支持向量机SVM的分类线
S代表的是边界上的样本点。得到的分割下如下图所示:

我们可以看出SVM在训练过程中找到的是两类点的分割线,计算样本中有少量异常点,在训练模型时依然能很正确的找到中间分割线,因为训练SVM时考虑了全量数据,确定这条线的b时只与支持向量点(边界上的点)有关。同样在测试集中就算有一些样本点是异常点也不会影响其正常分类,SVM具有抗干扰能力强的特点。
此外,由于训练SVM需要所有样本点参与模型训练,不然不能确定这条线,所以当数据量大时,SVM训练占用内存非常大。这是SVM模型的缺点。
8.2、二分类及多分类
SVM同样支持多分类,我们可以将一个多分类问题拆分成多个二分类问题,例如有A,B,C三类,我们使用SVM训练时可以训练3个模型,第一个模型针对是A类和不是A类进行训练。第二个模型针对是B类和不是B类进行训练。第三个模型针对是C类和不是C类进行训练。这样可以解决多分类问题。
9、SVM人脸识别实战
9.1、加载数据
import numpy as np
from sklearn.svm import SVC
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
from sklearn.metrics import accuracy_score
from sklearn import datasets
from sklearn.model_selection import GridSearchCV
# 加载人脸数据,labled faces wild
data = datasets.fetch_lfw_people(resize=1,min_faces_per_person=70)
X = data['data']
y = data['target']
faces = data['assets']
display(X.shape,faces.shape,y.shape)
target_names = data['target_names']
target_names9.2、数据查看
index = np.random.randint(0,1288,size = 1)[0]
face = X[index].reshape(125,94)
name = y[index] # 根据索引获取,名字
print(target_names[name])
display(face.shape)
plt.imshow(face,cmap = 'gray')9.3、数据降维
%%time
# 进行数据的降维
pca = PCA(n_components=0.95)
X_pca = pca.fit_transform(X)
display(X.shape,X_pca.shape)9.4、超参数筛选
svc = SVC()
X_train,X_test,y_train,y_test = train_test_split(X_pca,y,test_size=0.2,random_state=512)
params = {'C':np.logspace(-3,3,20),'kernel':['rbf','poly','linear'],'tol':[0.01,0.001,0.0001]}
gc = GridSearchCV(estimator = svc,param_grid = params,cv = 5)
gc.fit(X_train,y)9.5、最佳模型复训
svc = gc.best_estimator_
svc.fit(X_train,y_train)
print('训练数据得分:',svc.score(X_train,y_train))
print('测试数据的得分:',svc.score(X_test,y_test))9.6、可视化模型预测结果
plt.figure(figsize=(5 * 2, 10 * 3))
for i in range(50):
plt.subplot(10,5,i + 1) # 子视图
plt.imshow(faces_test[i],cmap = 'gray')
plt.axis('off') # 刻度关闭
# 是数字
true_name = target_names[y_test[i]].split(' ')[-1]
predict_name = target_names[y_pred[i]].split(' ')[-1]
plt.title('True:%s\nPred:%s' % (true_name,predict_name))