机器学习-分类算法支持向量机简要概述
文章目录
1. 监督学习与无监督学习
首先,简要理解一下 监督学习 和 无监督学习 。
- 监督学习 :
- 含义:给定输入和标签,训练得到一个模型,之后根据训练好的模型对没有标签的数据进行预测,得到该数据的标签。
- 特点:既有数据也有标签,切数据和标签之间存在联系
- 常见:分类(离散)、回归(连续)
- 无监督学习 :
- 含义:给定输入和特征,在不知道数据和特征之间关系的情况下,据聚类或一定的模型得到数据之间的关系。
- 特点:数据和特征之间没有联系或着找不出联系
- 常见:聚类算法
2. 支持向量机 ——SVM
2.1 线性可分
图片来源于百度百科
如上图所示,有两种类型的点,白点与黑点。SVM的目标,就是找出一个超平面(本图中是一条线,在二维数据中,超平面是一条线;在三维数据中,超平面就是一个平面;在n维数据中,超平面就是一个n-1维的对象),这个超平面将数据集分成两个部分,并且“间隔”最大。这个间隔如图中所示,是两条直线间的距离。
对于这条直线,是直线的向量方式,假设直线标准方程为:
a
x
+
b
y
+
c
=
0
ax + by + c = 0
ax+by+c=0
对其进行简单变换,函数形式:
f
(
x
,
y
)
=
(
a
,
b
)
(
x
y
)
+
c
f(x,y) = (a,b)(\begin{matrix} x \\ y \end{matrix}) + c
f(x,y)=(a,b)(xy)+c
此时进行简单替换,如下:
f
(
x
)
=
w
T
.
X
+
b
其
中
,
w
<
=
=
>
(
a
,
b
)
;
x
<
=
=
>
(
x
y
)
;
b
<
=
=
>
c
f(x) = w^T.X + b \\ 其中,w <==> (a,b);x <==> (\begin{matrix} x \\ y \end{matrix}); b <==> c
f(x)=wT.X+b其中,w<==>(a,b);x<==>(xy);b<==>c
上述式子只是超平面的一个简单示例,对于数据集中任何一个数据(x,y)代入式子计算,如果其值大于1,则是黑点,值小于-1,则是红点。如果值刚好等于1或者-1,则称这个点为支持向量(可见上图有3个支持向量)。如果值大于-1且小于1,则这个点处于间隔之内。
为了找寻满足”间隔“最大的超平面,看看间隔的计算公式:
d
=
2
∣
∣
w
∣
∣
d = {2 \over ||w||}
d=∣∣w∣∣2
公式中的w就是x与y系数a和b,要确定这个超平面,本质上就是确定参数w与b。
2.2 线性不可分
在线性不可分的情况下,支持向量机通过某种事先选择的非线性映射将输入变量映射到一个高维特征空间,在这个空间中构造最优分类超平面。此处不详谈,用一张图表示。其实本质还是找到一个超平面,由于低维空间找不到,所以就映射到高维空间,在高维空间寻找一个超平面,完成分类。
图片来源于 支持向量机通俗导论(理解SVM的三层境界)
2.3 核函数
核函数的本质也是将输入变量映射到高维空间,并寻找超平面。但它实际上是直接在原来的低维空间中进行计算,而不需要显式地写出映射后的结果。
下面列举几个常见的核:
- 线性核
K ( x 1 , x 2 ) = < x 1 , x 2 > K(x_1,x_2) = <x_1,x_2> K(x1,x2)=<x1,x2>
- 多项式核
K ( x 1 , x 2 ) = ( γ < x 1 , x 2 > + c ) 2 K(x_1,x_2) = (\gamma<x_1,x_2> + c)^2 K(x1,x2)=(γ<x1,x2>+c)2
- 高斯核 :可映射到无穷维空间
K ( x 1 , x 2 ) = e − ∣ ∣ x 1 − x 2 ∣ ∣ 2 2 σ 2 K(x_1,x_2) = e^{-{{{||x_1-x_2||}^2} \over {2\sigma^2}}} K(x1,x2)=e−2σ2∣∣x1−x2∣∣2
3. python sklearn中的使用(二分类问题)
3.1 SVC
SVC是支持向量分类,基于libsvm实现,数据拟合的时间复杂度是数据样本的二次方,可方便用于处理二分类问题。
def __init__(self, C=1.0, kernel='rbf', degree=3, gamma='auto_deprecated',
coef0=0.0, shrinking=True, probability=False,
tol=1e-3, cache_size=200, class_weight=None,
verbose=False, max_iter=-1, decision_function_shape='ovr',
random_state=None):
- 参数说明:
- C:惩罚项,float类型。可选参数,默认为1.0,C越大,对分错样本的惩罚程度越大,因此在训练样本中准确率越高,但是泛化能力会降低,也就是对测试数据的分类准确率降低。相反,减小C的话,容许训练样本中有一些误分类错误样本,泛化能力强。对于训练样本带有噪声的情况,一般采用后者,把训练样本集中错误分类的样本作为噪声。
- kernel:核函数类型,str类型,默认为’rbf’。可选参数为:
- ’linear’:线性核函数
- ‘poly’:多项式核函数
- ‘rbf’:径像核函数/高斯核
- ‘sigmod’:sigmod核函数
- precomputed’:核矩阵。precomputed表示自己提前计算好核函数矩阵,这时候算法内部就不再用核函数去计算核矩阵,而是直接用你给的核矩阵,核矩阵需要为n*n的
- degree:多项式核函数的阶数,int类型,可选参数,默认为3。这个参数只对多项式核函数有用,是指多项式核函数的阶数n,如果给的核函数参数是其他核函数,则会自动忽略该参数
- gamma:核函数系数,float类型,可选参数,默认为auto。只对’rbf’ ,’poly’ ,’sigmod’有效。如果gamma为auto,代表其值为样本特征数的倒数,即1/n_features
- coef0:核函数中的独立项,float类型,可选参数,默认为0.0。只有对’poly’ 和,’sigmod’核函数有用,是指其中的参数c
- probability:是否启用概率估计,bool类型,可选参数,默认为False,这必须在调用fit()之前启用,并且会fit()方法速度变慢
- shrinking:是否采用启发式收缩方式,bool类型,可选参数,默认为True
- tol:svm停止训练的误差精度,float类型,可选参数,默认为1e^-3
- cache_size:内存大小,float类型,可选参数,默认为200。指定训练所需要的内存,以MB为单位,默认为200MB
- class_weight:类别权重,dict类型或str类型,可选参数,默认为None。给每个类别分别设置不同的惩罚参数C,如果没有给,则会给所有类别都给C=1,即前面参数指出的参数C。如果给定参数’balance’,则使用y的值自动调整与输入数据中的类频率成反比的权重
- verbose:是否启用详细输出,bool类型,默认为False,此设置利用libsvm中的每个进程运行时设置,如果启用,可能无法在多线程上下文中正常工作。一般情况都设为False
- max_iter:最大迭代次数,int类型,默认为-1,表示不限制
- decision_function_shape:决策函数类型,可选参数’ovo’和’ovr’,默认为’ovr’。’ovo’表示one vs one,’ovr’表示one vs rest
- random_state:数据洗牌时的种子值,int类型,可选参数,默认为None。伪随机数发生器的种子,在混洗数据时用于概率估计
- 代码实例
plt.scatter(data_set[:,0],data_set[:,1],c=data_set[:,2]) # 绘制可视化图
plt.show()
对于上述书,我们用其对SVC进行训练再用训练好的SVC进行测试。
# 创建模型
clf = svm.SVC()
# 训练模型,参数sample_weight为每个样本设置权重,应对非均衡问题
clf.fit(X=train_data, y=train_target, sample_weight=None)
# 使用模型预测值
result = clf.predict(test_data)
# 输出预测值[-1. -1. 1. 1.]
print('预测结果:', result)
# 获得支持向量的索引
print('支持向量索引:',clf.support_)
# 为每一个类别获得支持向量的数量
print('支持向量数量:',clf.n_support_)
预测结果: [-1. -1. 1. 1.]
支持向量索引: [ 1 8 12 14 17 19 28 29 41 42 43 52 59 70 74 76 4 5 18 31 33 36 39 54
55 57 75 79 90]
支持向量数量: [16 13]
可见其预测结果还是挺准确的。
3.2 NuSVC
NuSVC(Nu-Support Vector Classification.): 核支持向量分类,和SVC类似,也是基于libsvm实现的,但不同的是通过一个参数 nu 支持向量的个数。
def __init__(self, nu=0.5, kernel='rbf', degree=3, gamma='auto_deprecated',
coef0=0.0, shrinking=True, probability=False, tol=1e-3,
cache_size=200, class_weight=None, verbose=False, max_iter=-1,
decision_function_shape='ovr', random_state=None):
其中参数 nu :训练误差的一个上界和支持向量的分数的下界。取值在(0,1 ]之间。其余参数与SVC一致。
clf = NuSVC() # 创建线性可分svm模型,参数均使用默认值
clf.fit(train_data, train_target) # 训练模型
result = clf.predict(test_data) # 使用模型预测值
print('预测结果:',result) # 输出预测值[-1. -1. 1. 1.]
# 获得支持向量的索引
print('支持向量索引:',clf.support_)
# 为每一个类别获得支持向量的数量
print('支持向量数量:',clf.n_support_)
预测结果: [-1. -1. 1. 1.]
支持向量索引: [ 0 1 8 9 10 12 14 17 19 23 24 28 29 30 41 42 43 52 56 58 59 70 74 76
97 98 99 2 4 5 6 13 16 18 26 31 33 36 39 46 48 50 54 55 57 69 72 75
78 79 80 82 83 88 90]
支持向量数量: [27 28]
3.3 LinearSVC
LinearSVC(Linear Support Vector Classification):线性支持向量分类,类似于SVC,但是其使用的核函数是”linear“。基于径向基函数计算的,其实现也不是基于LIBSVM,所以它具有更大的灵活性在选择处罚和损失函数时,而且可以适应更大的数据集,他支持密集和稀疏的输入是通过一对一的方式解决的。
def __init__(self, penalty='l2', loss='squared_hinge', dual=True, tol=1e-4,
C=1.0, multi_class='ovr', fit_intercept=True,
intercept_scaling=1, class_weight=None, verbose=0,
random_state=None, max_iter=1000):
-
参数说明:
-
C: 目标函数的惩罚系数C,用来平衡分类间隔margin和错分样本的,default C = 1.0
-
penalty : l1’ or ‘l2’ (default=’l2’) ,指定惩罚中使用的规范。 'l2’惩罚是SVC中使用的标准。 'l1’导致稀疏的coef_向量
-
loss: 指定损失函数
-
dual : 选择算法来解决对偶或原始优化问题。当
n s a m p l e s > n f e a t u r e s n_{samples}>n_{features} nsamples>nfeatures
时dual=false -
tol :(default = 1e - 3): svm结束标准的精度
-
multi_class: 如果y输出类别包含多类,用来确定多类策略, ovr表示一对多,“crammer_singer”优化所有类别的一个共同的目标 。如果选择“crammer_singer”,损失、惩罚和优化将会被被忽略
-
fit_intercept : 是否计算此模型的截距。 如果设置为false,则不会在计算中使用截距(即,预期数据已经居中)
-
intercept_scaling : 当self.fit_intercept为True时,实例向量x变为[x,self.intercept_scaling],即具有等于intercept_scaling的常量值的“合成”特征被附加到实例向量。 截距变为intercept_scaling *合成特征权重注意! 合成特征权重与所有其他特征一样经受l1 / l2正则化。 为了减小正则化对合成特征权重(并因此对截距)的影响,必须增加intercept_scaling
-
class_weight: 对于每一个类别i设置惩罚系数
C = c l a s s w e i g h t [ i ] ∗ C C=class_{weight}[i]∗C C=classweight[i]∗C
如果不给出,权重自动调整为
n s a m p l e s / ( n c l a s s e s ∗ n p . b i n c o u n t ( y ) ) n_{samples}/(n_{classes}∗np.bincount(y)) nsamples/(nclasses∗np.bincount(y)) -
verbose: 启用详细输出, 此设置利用liblinear中的每进程运行时设置,如果启用,可能无法在多线程上下文中正常工作
-
random_state : 在随机数据混洗时使用的伪随机数生成器的种子。 如果是int,则random_state是随机数生成器使用的种子; 如果是RandomState实例,则random_state是随机数生成器; 如果为None,则随机数生成器是np.random使用的RandomState实例
-
max_iter :要运行的最大迭代次数,默认为1000
-
-
实例
clf = LinearSVC() # 创建线性可分svm模型,参数均使用默认值
clf.fit(train_data, train_target) # 训练模型
result = clf.predict(test_data) # 使用模型预测值
print('预测结果:',result) # 输出预测值[-1. -1. 1. 1.]
预测结果: [-1. -1. 1. 1.]
4. 多分类问题
对于多分类问题,可通过SVM实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
# 创建不均衡样本
rng = np.random.RandomState(0)
n_samples_1 = 1000
n_samples_2 = 100
n_samples_3 = 100
X = np.r_[1.5 * rng.randn(n_samples_1, 2), 0.5 * rng.randn(n_samples_2, 2) + [2, 2],0.5 * rng.randn(n_samples_3, 2) + [-3, 3]]
# 三类样本点中心为(1.5,1.5)、(2,2)、(-3,3)
y = [0] * (n_samples_1) + [1] * (n_samples_2)+ [2] * (n_samples_3)
# 前面的1000个为类别0,后面的100个为类别1,最后100个类别为2
# 创建模型获取分离超平面
clf = svm.SVC(decision_function_shape='ovo',kernel='linear', C=1.0)
# decision_function_shape='ovo'为使用1对1多分类处理。会创建n(n-1)/2个二分类。ovr为一对所有的处理方式
clf.fit(X, y)
# 多分类的情况下,获取其中二分类器的个数。
dec = clf.decision_function([[1.5,1.5]]) # decision_function()的功能:计算样本点到分割超平面的函数距离。 包含几个2分类器,就有几个函数距离。
print('二分类器个数:',dec.shape[1])
# 绘制,第一个二分类器的分割超平面
w = clf.coef_[0]
a = -w[0] / w[1] # a可以理解为斜率
xx = np.linspace(-5, 5)
yy = a * xx - clf.intercept_[0] / w[1] # 二维坐标下的直线方程
# 使用类权重,获取分割超平面
wclf = svm.SVC(kernel='linear', class_weight={1: 10})
wclf.fit(X, y)
# 绘制 分割分割超平面
ww = wclf.coef_[0]
wa = -ww[0] / ww[1]
wyy = wa * xx - wclf.intercept_[0] / ww[1] # 带权重的直线
# 绘制第一个二分类器的分割超平面和样本点
h0 = plt.plot(xx, yy, 'k-', label='no weights')
h1 = plt.plot(xx, wyy, 'k--', label='with weights')
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.legend()
plt.show()
二分类器个数: 3
5. 回归
支持向量分类的方法可以被扩展用作解决回归问题. 这个方法被称作支持向量回归。
支持向量分类生成的模型(如前描述)只依赖于训练集的子集,因为构建模型的 cost function 不在乎边缘之外的训练点. 类似的,支持向量回归生成的模型只依赖于训练集的子集, 因为构建模型的 cost function 忽略任何接近于模型预测的训练数据。
支持向量分类有三种不同的实现形式: SVR, NuSVR 和 LinearSVR. 在只考虑线性核的情况下, LinearSVR 比 SVR 提供一个更快的实现形式, 然而比起 SVR 和 LinearSVR, NuSVR 实现一个稍微不同的构思(formulation)。
与分类的类别一样, fit方法会调用参数向量 X, y, 只在 y 是浮点数而不是整数型:
from sklearn import svm
X = [[0, 0], [2, 2]]
y = [0.5, 2.5]
clf = svm.SVR()
clf.fit(X, y)
print(clf.predict([[1, 1]]))
[1.5]