一、原理介绍
1. 算法简介
SVM全称是supported vector machine(支持向量机),即寻找到一个超平面使样本分成两类,并且间隔最大。

2. 超平面最大间隔介绍

3. 硬间隔和软间隔
3.1 硬间隔
- 严格地让所有实例都不在最大间隔之间,并且位于正确的一边,这就是硬间隔分类。
- 硬间隔分类有两个问题:
- 首先,它只在数据是线性可分离的时候才有效;
- 其次,它对异常值非常敏感。

3.2 软间隔
- 尽可能在保持最大间隔宽阔和限制间隔违例(即位于最大间隔之上,甚至在错误的一边的 实例)之间找到良好的平衡,这就是软间隔分类。
- 要避免这些问题,最好使用更灵活的模型。
- 目标是尽可能在保持间隔宽阔和限制间隔违例之间找到良好的平衡,这就是软间隔分类。
- 超参数C来控制这个平衡:
- C值越小,则间隔越宽,但是间隔违例也会越多。

二、算法原理
1. 推导目标函数

2. 拉格朗日乘子法
2.1 约束优化问题

2.2 Slater

2.3 KKT

三、核函数
1. 核函数
通过核函数能够解决在线性不可分场景下的分类,将原样本通过核函数映射到高维空间,即可更加容易划分;

2. 常见的核函数

3. 核函数的使用原则
- 一般有如下指导规则:
- 1) 如果Feature的数量很大,甚至和样本数量差不多时,往往线性可分,这时选用Sigmoid或者Linear线性核;
- 2) 如果Feature的数量很小,样本数量正常,不算多也不算少,这时选用RBF核;
- 3) 如果Feature的数量很小,而样本的数量很大,这时手动添加一些Feature,使得线性可分,然后选用Sigmoid或者Linear线性核;
- 4) 多项式核一般很少使用,效率不高,结果也不优于RBF;
- 5) Linear核参数少,速度快;RBF核参数多,分类结果非常依赖于参数,需要交叉验证或网格搜索最佳参数,比较耗时; 6)应用最广的应该就是RBF核,无论是小样本还是大样本,高维还是低维等情况,RBF核函数均适用。
四、SVM回归

五、SVM案例
1. API介绍
- sklearn中支持向量分类主要有三种方法:SVC、NuSVC、LinearSVC,扩展为三个支持向量回归方法:SVR、NuSVR、LinearSVR。
- SVC和NuSVC方法基本一致,唯一区别就是损失函数的度量方式不同
- NuSVC中的nu参数和SVC中的C参数;
- LinearSVC是实现线性核函数的支持向量分类,没有kernel参数。
1.1 SVC
- class sklearn.svm.SVC(C=1.0, kernel=’rbf’, degree=3,coef0=0.0,random_state=None)
- C: 惩罚系数,用来控制损失函数的惩罚系数,类似于线性回归中的正则化系数。
- C越大,相当于惩罚松弛变量,希望松弛变量接近0,即对误分类的惩罚增大,趋向于对训练集全分对的情况,这样会出现训练集测试时准确率很高,但泛化能力弱,容易导致过拟合。
- C值小,对误分类的惩罚减小,容错能力增强,泛化能力较强,但也可能欠拟合。
- C: 惩罚系数,用来控制损失函数的惩罚系数,类似于线性回归中的正则化系数。
- kernel:算法中采用的核函数类型,核函数是用来将非线性问题转化为线性问题的一种方法。
- 参数选择有RBF, Linear, Poly, Sigmoid或者自定义一个核函数。
- 默认的是”RBF”,即径向基核,也就是高斯核函数;
- 而Linear指的是线性核函数,
- Poly指的是多项式核,
- Sigmoid指的是双曲正切函数tanh核;。
- degree:
- 当指定kernel为’poly’时,表示选择的多项式的最高次数,默认为三次多项式;
- 若指定kernel不是’poly’,则忽略,即该参数只对’poly’有用。
- 多项式核函数是将低维的输入空间映射到高维的特征空间。
- coef0: 核函数常数值(y=kx+b中的b值),
- 只有‘poly’和‘sigmoid’核函数有,默认值是0。
1.2 NuSVC
- class sklearn.svm.NuSVC(nu=0.5)
- nu: 训练误差部分的上限和支持向量部分的下限,取值在(0,1)之间,默认是0.5
1.3 LinearSVC
- class sklearn.svm.LinearSVC(penalty=’l2’, loss=’squared_hinge’, dual=True, C=1.0)
- penalty:正则化参数, L1和L2两种参数可选,仅LinearSVC有。
- loss:损失函数,
- 有hinge和squared_hinge两种可选,前者又称L1损失,后者称为L2损失,默认是squared_hinge,
- 其中hinge是SVM的标准损失,squared_hinge是hinge的平方
- dual:是否转化为对偶问题求解,默认是True。
- C:惩罚系数, 用来控制损失函数的惩罚系数,类似于线性回归中的正则化系数
六、数字识别案例
1. 案例背景介绍

2. 数据介绍
数据文件train.csv和test.csv包含从0到9的手绘数字的灰度图像。 每个图像的高度为28个像素,宽度为28个像素,总共为784个像素。 每个像素具有与其相关联的单个像素值,指示该像素的亮度或暗度,较高的数字意味着较暗。该像素值是0到255之间的整数,包括0和255。 训练数据集(train.csv)有785列。第一列称为“标签”,是用户绘制的数字。其余列包含关联图像的像素值。 训练集中的每个像素列都具有像pixelx这样的名称,其中x是0到783之间的整数,包括0和783。为了在图像上定位该像素,假设我们已经将x分 解为x = i * 28 + j,其中i和j是0到27之间的整数,包括0和27。然后,pixelx位于28 x 28矩阵的第i行和第j列上(索引为零)。

3. 代码实现
#!/usr/bin/env python
# coding: utf-8
# In[1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from sklearn.model_selection import train_test_split
# # 获取数据
# In[2]:
train = pd.read_csv("./data/train.csv")
# In[4]:
train.head()
# In[6]:
train.shape
# ## 确定特征值\目标值
# In[7]:
train_image = train.ix[:, 1:]
# In[8]:
train_image.head()
# In[9]:
train_label = train.ix[:, 0]
# In[10]:
train_label.head()
# ## 查看具体图像
# In[14]:
num = train_image.ix[0,].values.reshape(28, 28)
# In[15]:
plt.imshow(num)
plt.axis("off")
plt.show()
# In[16]:
def to_plot(n):
num = train_image.ix[n,].values.reshape(28, 28)
plt.imshow(num)
plt.axis("off")
plt.show()
# In[19]:
to_plot(n=40)
# # 数据基本处理
# In[22]:
train_image.head()
# ## 数据归一化处理
# In[23]:
# 对数据特征值归一化处理
train_image = train_image.values / 255
# In[26]:
train_label = train_label.values
# ## 数据集分割
# In[28]:
x_train, x_val, y_train, y_val = train_test_split(train_image, train_label, train_size = 0.8, random_state=0)
# In[30]:
print(x_train.shape, x_val.shape)
# # 特征降维和模型训练
# In[32]:
import time
from sklearn.decomposition import PCA
# 多次使用pca,确定最后的最优模型
def n_components_analysis(n, x_train, y_train, x_val, y_val):
# 记录开始时间
start = time.time()
# pca降维实现
pca = PCA(n_components=n)
print("特征降维,传递的参数为:{}".format(n))
pca.fit(x_train)
# 在训练集和测试集进行降维
x_train_pca = pca.transform(x_train)
x_val_pca = pca.transform(x_val)
# 利用svc进行训练
print("开始使用svc进行训练")
ss = svm.SVC()
ss.fit(x_train_pca, y_train)
# 获取accuracy结果
accuracy = ss.score(x_val_pca, y_val)
# 记录结束时间
end = time.time()
print("准确率是:{}, 消耗时间是:{}s".format(accuracy, int(end-start)))
return accuracy
# In[34]:
# 传递多个n_components,寻找合理的n_components:
n_s = np.linspace(0.70, 0.85, num=5)
accuracy = []
for n in n_s:
tmp = n_components_analysis(n, x_train, y_train, x_val, y_val)
accuracy.append(tmp)
# In[35]:
# 准确率可视化展示
plt.plot(n_s, np.array(accuracy), "r")
plt.show()
# 经过图形展示,选择合理的n_components, 最后综合考虑确定结果为:0.80
# # 确定最优模型
# In[36]:
pca = PCA(n_components=0.80)
pca.fit(x_train)
pca.n_components_
# In[37]:
x_train_pca = pca.transform(x_train)
x_val_pca = pca.transform(x_val)
# In[39]:
print(x_train_pca.shape, x_val_pca.shape)
# In[40]:
# 训练比较优的模型,计算accuracy
ss1 = svm.SVC()
ss1.fit(x_train_pca, y_train)
ss1.score(x_val_pca, y_val)
# In[ ]: