【python库学习】 sklearn中的支持向量模型svm模块
原理
SVM 支持向量的原型最开始是从一个二分类任务得到的.有一个二分类,标签y取值{+1,-1},想要进行分类,则要在样本中寻找一个超平面可以将样本分为两类,该超平面可以定义为
w
x
+
b
=
0
wx+b=0
wx+b=0 其中w是法向量,则任意样本到超平面的距离为
γ
=
∣
w
x
+
b
∣
∥
w
∥
\gamma=\frac {|wx+b|}{\| w\|}
γ=∥w∥∣wx+b∣,该公式是由向量投影推导出点到直线的距离公式.
我们希望全部正确分类,则有
y
(
w
x
+
b
)
>
=
1
y(wx+b)>=1
y(wx+b)>=1由此样本到超平面的最小距离为
γ
=
1
∥
w
∥
\gamma=\frac {1}{\| w\|}
γ=∥w∥1.为了分类效果最佳,我们的目标就是使得这个最小距离最大,即
max
1
∥
w
∥
s
.
t
y
(
w
x
+
b
)
−
1
>
=
0
\max \frac {1}{\| w\|}\\s.t \space\space y(wx+b)-1>=0
max∥w∥1s.t y(wx+b)−1>=0 等价于最小化
min
1
2
∥
w
∥
2
s
.
t
y
(
w
x
+
b
)
−
1
>
=
0
\min \frac {1}{2}{\| w\|}^2 \\ s.t \space\space {y(wx+b)-1>=0}
min21∥w∥2s.t y(wx+b)−1>=0
接下来就是求解,引入拉格朗日式子,求导等于0,将w,b进行替换就得到了上面式子的对偶问题
min
∑
i
=
1
n
α
i
−
1
2
∑
i
=
1
n
∑
j
=
1
n
α
i
α
j
y
i
y
j
x
j
T
x
i
K
K
T
:
{
α
i
≥
0
y
i
f
(
x
i
)
−
1
≥
0
α
i
(
y
i
f
(
x
i
)
−
1
)
=
0
\min \space \displaystyle\sum_{i=1}^n \alpha_i -\frac 1 2 \displaystyle\sum_{i=1}^n \displaystyle\sum_{j=1}^n \alpha_i \alpha_j y_i y_j x_j^Tx_i \\ KKT:\begin{cases} \alpha_i \ge0 \\ y_if(x_i)-1 \ge0 \\ \alpha_i(y_if(x_i)-1)=0 \end{cases}
min i=1∑nαi−21i=1∑nj=1∑nαiαjyiyjxjTxiKKT:⎩
⎨
⎧αi≥0yif(xi)−1≥0αi(yif(xi)−1)=0其中约束条件转化为KKT条件.条件中
f
(
x
i
)
=
w
x
i
+
b
f(x_i)=wx_i+b
f(xi)=wxi+b.KKT最后一个条件
α
=
0
\alpha=0
α=0时表明样本被忽略,不为0时,式子
y
i
f
(
x
i
)
−
1
=
0
y_if(x_i)-1=0
yif(xi)−1=0为支持向量.
通过SMO等求解算法得到拉格朗日算子
α
\alpha
α的解,由此得到最优解
w
∗
w^*
w∗,代入一个支持向量就可以得到
b
∗
b^*
b∗.至此该模型的求解就完成了,原型也如上所示.
通过上述原理也可以得到该模型的决策函数由支持向量决定,模型的决策函数为
f
(
x
)
=
s
g
n
(
w
∗
T
x
+
b
∗
)
=
s
g
n
(
∑
i
=
1
n
α
i
y
i
x
i
T
x
+
b
∗
)
f(x)=sgn( w^{*T}x+b^*)\\=sgn(\displaystyle\sum_{i=1}^n \alpha_i y_i x_i^Tx+b^* )
f(x)=sgn(w∗Tx+b∗)=sgn(i=1∑nαiyixiTx+b∗)其中取
α
i
>
0
\alpha_i>0
αi>0下对应的支持向量,sgn为阶跃函数,大于0输出1,等于0输出0,小于0输出-1.
软间隔
说完原理,我们看到上面的假设是严格分类,有时较难求出最优解,若允许部分样本超过最小间隔,当然希望尽可能减少越过的样本数,则目标函数变为下方形式
min
1
2
∥
w
∥
2
+
C
∑
i
=
1
n
m
a
x
(
0
,
1
−
y
i
(
w
i
x
+
b
)
)
−
−
(
1
)
\min \frac 1 2 \|w\|^2+C\displaystyle\sum_{i=1}^n max(0,1-y_i(w_ix+b)) --(1)\\
min21∥w∥2+Ci=1∑nmax(0,1−yi(wix+b))−−(1)
引入松弛变量则该式子表示为
min
1
2
∥
w
∥
2
+
C
∑
i
=
1
n
ξ
i
s
.
t
.
{
y
i
(
w
x
i
+
b
)
+
ξ
i
−
1
≥
0
,
i
∈
[
1
,
n
]
ξ
i
≥
0
,
i
∈
[
1
,
n
]
\min \frac 1 2 \|w\|^2+C\displaystyle\sum_{i=1}^n \xi_i\\ \\s.t. \space\space \begin{cases}y_i(wx_i+b)+\xi_i-1\ge0 \space ,i\in [1,n] \\ \xi_i\ge0 \space ,i\in [1,n]\end{cases}
min21∥w∥2+Ci=1∑nξis.t. {yi(wxi+b)+ξi−1≥0 ,i∈[1,n]ξi≥0 ,i∈[1,n]
该公式(1)从另外一角度也可以理解为经验风险项+正则化项.经验风险项可以选择其它形式,即当前常见的损失函数形式,公式中的形式为Hinge损失函数.接下来按正常流程进行求解.
核函数
当遇到线性不可分的场景,考虑将其转化到高纬空间使其可分.由此需要对样本进行转化,则x变为
ϕ
(
x
)
\phi(x)
ϕ(x),原公式中X进行相应的切换.该难点是很难确定具体的
ϕ
(
x
)
\phi(x)
ϕ(x)是什么样的,因此定义核函数为
k
(
x
i
,
x
j
)
=
ϕ
(
x
i
)
T
ϕ
(
x
j
)
k(x_i,x_j)=\phi(x_i)^T\phi(x_j)
k(xi,xj)=ϕ(xi)Tϕ(xj),核矩阵为
其中能成为核函数的要求是核矩阵总是半正定的,如此总能找到一个与核函数对应的
ϕ
(
x
)
\phi(x)
ϕ(x).
常见的核函数有
回归
用于回归任务时,其最小间隔就不是1了,而是f(x)与y偏差
ϵ
\epsilon
ϵ,同样为简化表示,引入松弛变量
min
1
2
∥
w
∥
2
+
C
∑
i
=
1
n
(
ξ
i
+
ξ
i
∗
)
s
.
t
.
{
y
i
−
f
(
x
i
)
≥
ξ
i
+
ϵ
,
i
∈
[
1
,
n
]
f
(
x
i
)
−
y
i
≥
ξ
i
∗
+
ϵ
,
i
∈
[
1
,
n
]
ξ
i
≥
0
,
ξ
i
∗
≥
0
,
i
∈
[
1
,
n
]
\min \frac 1 2 \|w\|^2+C\displaystyle\sum_{i=1}^n (\xi_i+ \xi_i^*)\\ \\s.t. \space\space \begin{cases}y_i-f(x_i)\ge\xi_i+\epsilon \space ,i\in [1,n] \\ f(x_i)-y_i\ge\xi_i^*+\epsilon \space ,i\in [1,n] \\ \xi_i\ge0 ,\xi_i^*\ge0\space ,i\in [1,n]\end{cases}
min21∥w∥2+Ci=1∑n(ξi+ξi∗)s.t. ⎩
⎨
⎧yi−f(xi)≥ξi+ϵ ,i∈[1,n]f(xi)−yi≥ξi∗+ϵ ,i∈[1,n]ξi≥0,ξi∗≥0 ,i∈[1,n]
优缺点
支持向量机模型可以用于分类,回归以及异常识别任务,具有以下优点
- 高维空间有效,特征维度高于样本数时仍然有效
- 内存占用小(存储支持向量集)
- 可扩展性好,支持不同核函数以应用不同场景,如下图所示
当然也具有一些限制:
- 当特征维度远大于样本数时,效果变差
- 该模型分类时不提供概率值,如需要获取概率,需要再进行一次转换(如softmax,平台缩放),添加额外的计算,且概率为近似值。
- 应用核函数遇到样本量大时,计算量过大,不适用。
- 难以选择合适的核函数
- 对缺失值敏感
1.分类
当前模有方法SVC,NuSVC与LinearSVC,NuSVC与SVC的区别在于使用了参数V来控制训练误差的上限与支持向量的下限,而SVC的正则参数是C。该模块方法使用如下,可以通过其属性support_vectors_查看重要的支持向量信息。
>>> from sklearn import svm
>>> # 训练集 X【样本数,特征】
>>> X = [[0, 0], [1, 1]]
>>> # 标签 y【样本数】
>>> y = [0, 1]
>>> clf = svm.SVC()
>>> clf.fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> # get support vectors
>>> clf.support_vectors_
array([[ 0., 0.],
[ 1., 1.]])
>>> # get indices of support vectors
>>> clf.support_
array([0, 1]...)
>>> # get number of support vectors for each class
>>> clf.n_support_
array([1, 1]...)
1.1多分类
方法SVC,NuSVC通过一VS一的方式进行分类,这意味着n类需要训练n*(n-1)/2 个分类器,而LinearSVC 采用的是一VS其余,n类训练n个分类器。为了使用中接口的统一,提供了参数decision_function_shape来进行选择。当使用一VS其余方法时遇到平局时,默认返回它们中的第一类,要想不使用默认需在predict方法中设置break_ties=True,但需注意的是该设置需消耗一定计算量。
>>> X = [[0], [1], [2], [3]]
>>> Y = [0, 1, 2, 3]
>>> clf = svm.SVC(decision_function_shape='ovo')
>>> clf.fit(X, Y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovo', degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> dec = clf.decision_function([[1]])
>>> dec.shape[1] # 4 classes: 4*3/2 = 6
6
>>> clf.decision_function_shape = "ovr"
>>> dec = clf.decision_function([[1]])
>>> dec.shape[1] # 4 classes
4
1.2得分与概率
SVC,NuSCV下的方法decision_function 给出来每个样本在每类上的得分,使用方法decision_function得到概率。在二分类中,使用Platt 缩放法实现,该方法使用SVC模型输出作为训练集,构建sigmod函数,原标签仍为标签,进行拟合参数求解,由此得到了概率输出。该方法,在遇到大数据集时,计算消耗会过大;且该概率与得分并不保持完全的正相关关系;可能还会出现模型输出为1类,而概率输出小于0.5的情况。在实际使用中建议不要使用概率输出而采用得分输出。
# 输出概率
>>> clf.predict_proba(X)
1.3 不平衡问题
当需要对某一类或某些样本给更多权重时,可以通过参数 class_weight 和 sample_weight进行设置。SVC 两个均支持设置,其他支持使用sample_weight进行设置,其中class_weight设置形式与生效效果对比如下
#{1:10} 中1表示为类,10表示权重值
wclf = svm.SVC(kernel="linear", class_weight={1: 10})
wclf.fit(X, y)
sample_weight设置与使用效果如下
#sample_weight_last_ten 为维度等于样本数的一位数组,元素初始均为1
# and bigger weights to some outliers
sample_weight_last_ten[15:] *= 5
# Fit the models.
# This other model takes into account some dedicated sample weights.
clf_weights = svm.SVC(gamma=1)
clf_weights.fit(X, y, sample_weight=sample_weight_last_ten)
2.回归
本库对回归实现有三个方法 SVR, NuSVR and LinearSVR,可以调用。三者实现上稍微有所不同,其中LinearSVR如其名所示只支持线性核。其使用方法与分类基本一致不再展开。
3.密度估计与异常识别
本库中的安排了类 OneClassSVM应用异常识别,这该部分放到异常识别方法集中进行讲解
复杂度为 O ( n s a m p l e s 2 × n f e a t u r e s ) O ( n s a m p l e s 3 × n f e a t u r e s ) O(n_samples^2 × n_ features) ~ O(n_samples^3 × n_ features) O(nsamples2×nfeatures) O(nsamples3×nfeatures)
4.实践注意事项
常用参数列表
SVC类共14个参数,其具体含义与使用建议如下:
参数名 | 参数含义 | 使用说明 |
---|---|---|
C | 正则系数 | 默认为1,惩罚力度与大小成反比,必须为正数 |
kernel | 核函数 | {‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’} or callable, default=’rbf’ |
degree | 多项式次数 | 与多项式核函数配对使用 |
gamma | 核函数系数 | {‘scale’, ‘auto’} or float, default=’scale’,‘rbf’, ‘poly’ and ‘sigmoid’中使用 |
coef0 | 核函数偏差系数 | 在‘poly’ and ‘sigmoid’中重要 |
shrinking | 缩放系数 | 默认True,使用见第5条 |
probability | 是否输出概率值 | 默认为False,使用见第7条,为true时需要额外的计算量 |
tol | 损失函数阈值 | default=1e-3,到达该阈值停止迭代 |
cache_size | 缓存大小 | 使用见第2条 |
class_weight | 类权重 | 使用见第6条以及前文 |
max_iter | 最大迭代次数 | 默认-1,不做限制 |
decision_function_shape | 多分类方法参数 | {‘ovo’, ‘ovr’}, default=’ovr’对应1V1,1v其他 |
break_ties | 解绑参数 | 见1.1多分类 |
random_state | 随机状态 | 使用见第7条 |
- 避免数据复制,当数据不是次序连续和双精度的时候,底层实现会复制数据集转成该格式,若数据集大,且无法避免复制时,推荐使用 SGDClassifier,其功能与LinearSVR基本类似。
- 若内存RAM允许,建议 cache_size设置 500(MB) or 1000(MB),默认是200M;来加快运算速度。
- 惩罚系数C默认为1,在没有太多异常值时,建议使用默认设置
- 建议对数据进行归一化或者标准化处理;
- 参数shrinking,在迭代次数很多时设置该参数可加快训练速度;而如果设置更大的停止阈值,建议不设置该参数会更快
- 遇到类别不平衡,可以设置 class_weight=‘balanced’ 或者尝试不同数值的惩罚系数C.
- 随机性:一、如果输出概率probability is set to True时,其底层实现会生成随机数来打乱数据集来估计概率;可以通过random_state 来控制随机状态。二、如果dual设置为True时,LinearSVR在训练时会采用随机特征选择策略,可以通过random_state 来控制随机状态。
- LinearSVR使用1阶惩罚项时( LinearSVC(penalty=‘l1’, dual=False)),可以产生更稀疏的决策函数,通过设置惩罚系数C进行稀疏程度控制,其中C越大,所得模型越复杂;为保证模型不为空,可以通过sklearn.svm.l1_min_c获取模型不为空下的C的最低阈值,来指导C的设置。
- 模型 NuSVC/OneClassSVM/NuSVR参数nu 区间在0到1之间,该参数给出样本越过边界误差占比的上限,即样本中支持向量占比的下限。