学习目标:
学习目标:
在很久以前的情人节,英雄要去救他的爱人,但魔鬼和他玩了一个游戏。魔鬼在桌子上似乎有规律放了两种颜色的球,说:“你用一根棍分开它们。要求:尽量在放更多球之后,仍然适用。”。
于是英雄这样放。似乎干的不错?
然后魔鬼又在桌上放了更多的球,但似乎有一个球站错了阵营。
那怎么办?
英雄试图通过在棍子的两侧留出尽可能大的间隙来将棍子放在最佳位置。
SVM 就是试图把棍放在最佳位置,好让在棍的两边有尽可能大的间隙
现在即使魔鬼放了更多的球,棍仍然是一个好的分界线。
然后,在 SVM 工具箱中有另一个更加重要的技巧(trick)。魔鬼看到英雄已经学会了一个trick,于是魔鬼给了英雄一个新的挑战。
现在,英雄没有棍可以很好帮他分开两种球了,现在怎么办呢?
当然像电影中一样,英雄桌子一拍,球飞到空中。然后,凭借英雄的轻功抓起一张纸,插到了两种球的中间。
现在,从魔鬼的角度看这些球,这些球看起来像是被一条曲线分开了。
再之后,无聊的大人们,把上面的物体起了别名:
案例来源: Support Vector Machines explained well
支持向量机直观感受:SVM with polynomial kernel visualization
SVM 全称是 Supported Vector Machine(支持向量机),即寻找到一个超平面使样本分成两类,并且间隔最大。
SVM 能够执行线性或非线性分类、回归,甚至是异常值检测任务。它是机器学习领域最受欢迎的模型之一。
SVM 特别适用于中小型复杂数据集的分类。
Q:SVM 只能做二分类吗?
A:SVM 最初是为二分类问题设计的,但它也可以用于多分类问题。目前,构造 SVM 多类分类器的方法主要有两类:一类是直接法,直接在目标函数上进行修改,将多个分类面的参数求解合并到一个最优化问题中,通过求解该最优化问题“一次性”实现多类分类。另一类是间接法,主要是通过组合多个二分类器来实现多分类器的构造,常见的方法有one-against-one和one-against-all两种。
上左图显示了三种可能的线性分类器的决策边界:
对于左图的两个实现模型而言,如果数据集稍微有一点小变动,那么就分错了,所以泛化性能可能有些不理想
右图中的实线代表 SVM 分类器的决策边界(具体是怎么分开的),两条虚线之间的距离表示最大间隔。实现模型不仅分离了两个类别,且尽可能远离最近的训练实例。
SVM 不仅仅要找到划分的线,而且要求线离两个实例的举例越大越好,这样就有足够的距离,从而提升对新数据集的包容。
在上面我们使用超平面进行分割数据的过程中,如果我们严格地让所有实例都不在最大间隔之间,并且位于正确的一边,这就是硬间隔分类。
简单来说,硬间隔就是要求百分百分对!
硬间隔分类有两个问题:
举例:当有一个额外异常值的鸢尾花数据:
要避免硬间隔因异常值出现的不可分的问题,最好使用更灵活的模型。目标是尽可能在保持最大间隔宽阔和限制间隔违例(即位于最大间隔之上,甚至在错误的一边的实例)之间找到良好的平衡,这就是软间隔分类。
间隔违例:指位于最大间隔之上,甚至在错误的一边的实例。
简单来说,硬间隔(hard margin)是指在SVM中,我们假设数据是线性可分的,也就是说,我们可以找到一个超平面将不同类别的数据完全分开。但是,在现实世界中,数据往往不是线性可分的。为了解决这个问题,我们引入了软间隔(soft margin)的概念。软间隔允许一些数据点被错误分类,以便更好地拟合数据。这样,我们就可以在最大化间隔的同时,尽量减少不满足约束的样本数量。
在 Scikit-Learn 的 SVM 类中,可以通过超参数 C 来控制这个平衡:
超参数 C 我们可以理解为是一个惩罚项。C 越大,惩罚越重,间隔违例就越少,说明间隔宽度越小;C 越小,惩罚越轻,间隔违例就越多,说明间隔宽度就越大。
上图显示了在一个非线性可分离数据集上,两个软间隔 SVM 分类器各自的决策边界和间隔。
看起来第二个分类器的泛化效果更好,因为大多数间隔违例实际上都位于决策边界正确的一边,所以即便是在该训练集上,它做出的错误预测也会更少。
小结:
学习目标:
from sklearn import svm
作用:from sklearn import svm
这行代码是从 sklearn
库中导入 svm
模块。svm
模块中主要有 LinearSVC
、NuSVC
和 SVC
三种方法,用于支持向量机分类。
方法一:LinearSVC
方法(Linear Support Vector Classification,意为线性支持向量分类)
penalty
: 正则化参数,可选值为 ‘l1’ 和 ‘l2’,仅适用于 LinearSVC。loss
: 损失函数,可选值为 ‘hinge’ 和 ‘squared_hinge’。其中
dual
: 是否转化为对偶问题求解,默认为 True。tol
: 残差收敛条件,默认为 0.0001。C
: 惩罚系数,用来控制损失函数的惩罚系数。multi_class
: 负责多分类问题中分类策略制定,可选值为 ‘ovr’ 和 ‘crammer_singer’。fit_intercept
: 是否计算截距。class_weight
: 用来处理不平衡样本数据的,可以直接以字典的形式指定不同类别的权重,也可以使用 ‘balanced’ 参数值。verbose
: 是否冗余,默认为 False。random_state
: 随机种子的大小。max_iter
: 最大迭代次数,默认为 1000。coef_
: 各特征的系数(重要性)。intercept_
: 截距的大小(常数值)。decision_function(X)
: 获取数据集 X 到分离超平面的距离。fit(X, y)
: 在数据集 (X,y) 上使用 SVM 模型。get_params([deep])
: 获取模型的参数。predict(X)
: 预测数据值 X 的标签。score(X,y)
: 返回给定测试集和对应标签的平均准确率。方法二:NuSVC
方法( Nu-Support Vector Classification,意为 Nu-支持向量分类)
作用:是一种支持向量分类器,它允许用户控制支持向量的数量。它可以处理非线性可分的数据集,但对于大规模的数据集,拟合时间可能会很长。
参数:
nu
: 训练误差部分的上限和支持向量部分的下限,取值在(0,1)之间,默认为 0.5。kernel
: 核函数,可选值为 ‘linear’、‘poly’、‘rbf’、‘sigmoid’ 和 ‘precomputed’。degree
: 当核函数为多项式核函数时,用来控制函数的最高次数。gamma
: 核函数系数,默认为 ‘auto’。coef0
: 核函数常数值,只有 ‘poly’ 和 ‘sigmoid’ 核函数有,默认值为 0。shrinking
: 是否采用启发式收缩,默认为 True。probability
: 是否使用概率估计,默认为 False。tol
: 停止拟合容忍度,默认为 0.001。cache_size
: 缓冲大小,默认为 200MB。class_weight
: 各类权重,与其他模型中参数含义类似,也是用来处理不平衡样本数据的,可以直接以字典的形式指定不同类别的权重,也可以使用 ‘balanced’ 参数值。verbose
: 是否冗余,默认为 False。max_iter
: 最大迭代次数,默认为 -1。decision_function_shape
: 与 ‘multi_class’ 参数含义类似。random_state
: 随机种子的大小 。返回值:
support_
: 以数组的形式返回支持向量的索引。support_vectors_
: 返回支持向量。n_support_
: 每个类别支持向量的个数。dual_coef_
: 支持向量系数。coef_
: 每个特征系数(重要性),只有核函数是 LinearSVC 的时候可用。intercept_
: 截距值(常数值)。方法三:SVC
方法(C-Support Vector Classification,意为 C-支持向量分类)
C
: 惩罚系数。与 NuSVC 方法基本一致,唯一区别就是损失函数的度量方式不同(NuSVC 中的 nu 参数和 SVC 中的 C 参数)。举例:
from sklearn import svm
# 1. 准备数据
X = [[0, 0], [1, 1]]
y = [0, 1]
# 2. 定义模型
clf = svm.SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape="ovr", degree=3, gamma="scale", kernel="rbf",
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
# 3. 模型训练
clf.fit(X, y)
# 4. 预测
clf.predict([[2, 2]])
array([1])
学习目标:
假设给定一个特征空间上的训练集为:
T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T = \{ (x_1, y_1), (x_2, y_2), ..., (x_N, y_N) \} T={(x1,y1),(x2,y2),...,(xN,yN)}
x i ∈ R n ( 实数 ) y i ∈ { + 1 , − 1 } i = 1 , 2 , . . . , N \begin{aligned} & x_i \in R^n(实数)\\ & y_i \in \{ +1, -1 \}\\ & i = 1, 2, ..., N \end{aligned} xi∈Rn(实数)yi∈{+1,−1}i=1,2,...,N
其中, ( x i , y i ) (x_i, y_i) (xi,yi) 称为样本点。
Q:为什么正负用 ( − 1 , 1 ) (-1, 1) (−1,1) 表示呢?
A:其实这里没有太多原理,就是一个标记,你也可以用 ( 2 , − 3 ) (2,-3) (2,−3) 来标记,只是为了方便。
使用 ( − 1 , 1 ) (-1, 1) (−1,1) 则在 y i y j = y i ∗ y j \frac{y_i}{y_j} = y_i * y_j yjyi=yi∗yj 的过程中刚好可以相等,便于之后的计算。
给定了上面提出的线性可分训练数据集,通过间隔最大化得到分离超平面,为:
y ( x ) = w T Φ ( x ) + b y(x) = w^T\Phi(x) + b y(x)=wTΦ(x)+b
其中:
相应的分类决策函数为:
f ( x ) = s i g n ( w T Φ ( x ) + b ) f(x) = \mathrm{sign}(w^T\Phi(x) + b) f(x)=sign(wTΦ(x)+b)
以上的决策函数就称为线性可分支持向量机。
这里解释一下 Φ \Phi Φ:
这是某个确定的特征空间转换函数,它的作用是将 x x x 映射到更高的维度,它有一个以后我们经常会见到的专有称号“核函数(Kernel Function)”。
比如我们看到的特征有2个:
x 1 , x 2 x_1, x_2 x1,x2 组成最先见到的线性函数 w 1 x 1 + w 2 x 2 w_1x_1 + w_2 x_2 w1x1+w2x2。
但也许这两个特征并不能很好地描述数据,于是我们进行维度的转化,转化到五维特征空间,变成:
w 1 x 1 + w 2 x 2 + w 3 x 1 x 2 + w 4 x 1 2 + w 5 x 2 2 w_1x_1 + w_2x_2 + w_3x_1x_2 + w_4x_1^2 + w_5x_2^2 w1x1+w2x2+w3x1x2+w4x12+w5x22
于是我们多了三个特征。
以上就是笼统地描述 Φ \Phi Φ 是如何对 x x x 映射的。
Φ \Phi Φ 最简单的映射就是:
Φ ( x ) = x \Phi(x) = x Φ(x)=x
即不进行任何映射。
以上就是线性可分支持向量机的模型表达式。我们要去求出这样一个模型,或者说这样一个超平面 y ( x ) y(x) y(x),它能够最优地分离两个集合。
其实也就是我们要去求一组参数 ( w , b ) (w,b) (w,b) 使其构建的超平面函数能够最优地分离两个集合。
核函数 Φ \Phi Φ 是已知的,不需要我们求。
如下就是一个最优超平面:
硬间隔分类
又比如说这样:
阴影部分是一个“过渡带”,“过渡带”的边界是集合中离超平面最近的样本点落在的地方。
软间隔分类
我们知道了支持向量机是个什么东西了。现在我们要去寻找这个支持向量机,也就是寻找一个最优的超平面。于是我们要建立一个目标函数。那么如何建立呢?
再来看一下我们的超平面表达式:
y ( x ) = w T Φ ( x ) + b y(x) = w^T\Phi(x) + b y(x)=wTΦ(x)+b
其中: y ( x ) y(x) y(x) 表示样本 x x x 到分离超平面的距离。
为了方便,我们让核函数不进行映射,即 Φ ( x ) = x \Phi(x) = x Φ(x)=x。那么在样本空间中,划分超平面可通过如下线性方程来描述:
w T x + b = 0 w^Tx+b = 0 wTx+b=0
我们知道:
要让点到线的距离最近,要垂直,所以称为法向量。
显然,划分超平面可被法向量 w w w 和位移 b b b 确定,我们把其记为 ( w , b ) (w,b) (w,b)。
于是,样本空间中任意点 x x x 到超平面 ( w , b ) (w,b) (w,b) 的距离可写成:
r = ∣ w T x + b ∣ ∣ ∣ w ∣ ∣ r = \frac{|w^Tx + b|}{||w||} r=∣∣w∣∣∣wTx+b∣
∣ ∣ w ∣ ∣ ||w|| ∣∣w∣∣ 就是求向量 w w w 的 2-范数。
范数的说明:【文间跳转】范数说明
假设超平面 ( w , b ) (w, b) (w,b) 能将训练样本正确分类,即对于 ( x i , y i ) ∈ D (x_i, y_i) \in D (xi,yi)∈D:
令
{ w T x i + b ≥ + 1 , y i = + 1 ; w T x i + b ≤ − 1 , y i = − 1 ; \begin{cases} w^Tx_i + b \ge +1, & y_i = +1; \\ w^Tx_i + b \le -1, & y_i = -1; \\ \end{cases} {wTxi+b≥+1,wTxi+b≤−1,yi=+1;yi=−1;
如图所示,距离超平面最近的几个训练样本点使上式等号成立,他们被称为“支持向量”,则两个异类支持向量到超平面的距离之和为: y = 2 ∣ ∣ w ∣ ∣ y = \frac{2}{||w||} y=∣∣w∣∣2,它被称为“间隔”。
支持向量才是真正决定间隔的数据。
想要找到具有最大间隔的划分超平面,也就是要找到能满足下式中约束的参数 w w w 和 b b b,使得 r r r 最大。
{ w T x i + b ≥ + 1 , y i = + 1 w T x i + b ≤ − 1 , y i = − 1 \begin{cases} w^Tx_i + b \ge +1, & y_i = +1\\ w^Tx_i + b \le -1, & y_i = -1 \end{cases} {wTxi+b≥+1,wTxi+b≤−1,yi=+1yi=−1
即:
max w , b = 2 ∣ ∣ w ∣ ∣ s.t. y i ( w T x i + b ) ≥ + 1 , i = 1 , 2 , . . . , m \underset{w, b}{\max} = \frac{2}{||w||} \quad \text{s.t.} \quad y_i(w^Tx_i + b) \ge +1, \quad i=1, 2, ..., m w,bmax=∣∣w∣∣2s.t.yi(wTxi+b)≥+1,i=1,2,...,m
在数学公式中,“s.t.” 是 “such that” 的缩写,意为“使得”或“满足条件”。它用来引入一些限制条件或约束条件。
例如,在优化问题中,我们通常会看到这样的形式: min x f ( x ) s.t. g ( x ) ≤ 0 \min_x f(x) \quad \text{s.t.} \quad g(x) \leq 0 xminf(x)s.t.g(x)≤0
这表示我们要最小化目标函数 f ( x ) f(x) f(x),使得 g ( x ) ≤ 0 g(x) \leq 0 g(x)≤0 这个约束条件得到满足。
所以上式的意思就是:求得 2 ∣ ∣ w ∣ ∣ \frac{2}{||w||} ∣∣w∣∣2 的最大值,使得 y i ( w T x i + b ) ≥ 1 y_i(w^Tx_i + b) \ge 1 yi(wTxi+b)≥1 满足。
显然,为了最大化间隔,仅需要最大化 ∣ ∣ w ∣ ∣ − 1 ||w||^{-1} ∣∣w∣∣−1,这等价于最小化 ∣ ∣ w ∣ ∣ 2 ||w||^2 ∣∣w∣∣2。于是上式可以重写为:
max w , b = 1 2 ∣ ∣ w ∣ ∣ 2 s.t. y i ( w T x i + b ) ≥ + 1 , i = 1 , 2 , . . . , m \underset{w, b}{\max} = \frac{1}{2}||w||^2 \quad \text{s.t.} \quad y_i(w^Tx_i + b) \ge +1, \quad i=1, 2, ..., m w,bmax=21∣∣w∣∣2s.t.yi(wTxi+b)≥+1,i=1,2,...,m
这就是支持向量机的基本型。
到这一步,终于把目标函数给建立起来了。那么下一步自然是去求目标函数的最优值。因为目标函数带有一个约束条件,所以我们可以用拉格朗日乘子法求解。
拉格朗日乘子法(Lagrange multipliers)是一种寻找多元函数在一组约束下的极值的方法。通过引入拉格朗日乘子,可将有 d d d 个变量与 k k k 个约束条件的最优化问题转化为具有 d + k d + k d+k 个变量的无约束优化问题求解。
【文间跳转】拉格朗日乘子法举例复习
经过朗格朗日乘子法,我们可以把目标函数转换为:
L ( w , b , α ) = 1 2 ∣ ∣ w ∣ ∣ 2 − ∑ i = 1 n α i ( y i ( w T ⋅ Φ ( x i ) + b ) − 1 ) L(w, b, \alpha) = \frac{1}{2} ||w||^2 - \sum_{i=1}^n \alpha_i(y_i(w^T \cdot \Phi(x_i) + b) - 1) L(w,b,α)=21∣∣w∣∣2−i=1∑nαi(yi(wT⋅Φ(xi)+b)−1)
其中,上式后半部分:
− ∑ i = 1 n α i ( y i ( w T ⋅ Φ ( x i ) + b ) − 1 ) = 0 -\sum_{i=1}^n \alpha_i(y_i(w^T \cdot \Phi(x_i) + b) - 1) = 0 −i=1∑nαi(yi(wT⋅Φ(xi)+b)−1)=0
走到这一步,这个目标函数还是不能开始求解,现在我们的问题是极小极大值问题。
我们要将其转换为对偶问题,变成极大极小值问题:
从 min max L ( w , b , α ) 变为 max α min w , b L ( w , b , α ) 从 \min \max L(w, b, \alpha) \quad 变为 \quad \underset{\alpha}{\max} \underset{w, b}{\min} L(w, b, \alpha) 从minmaxL(w,b,α)变为αmaxw,bminL(w,b,α)
在最优化问题中,对偶问题是指通过转换原问题来求解最优目标函数的一种方法。通俗来讲,对偶问题就是使求解更加高效且目标函数值不变,通过先消去 w w w, b b b,得到关于 α \alpha α 的函数,然后单独计算 α \alpha α ,通过得到的 α \alpha α 反求 w w w, b b b,最后获得超平面的参数,相比于先对 α \alpha α 的不等式约束进行计算,对偶的方式使得计算更加便捷。
简单来说:对于一个函数而言,它的极大值中的极小值就是极小值中的极大值(注意,这句话其实是有很大问题的,这里主要是为了理解)。
参考资料: 运筹学_8 对偶问题概念 转换方法
如何获取对偶函数?
首先我们对原目标函数的 w w w 和 b b b 分别求导:
然后将以上 w w w 和 b b b 的求导函数重新代入原目标函数的 w w w 和 b b b 中,得到的就是原函数的对偶函数:
L ( w , b , α ) = 1 2 ∣ ∣ w ∣ ∣ 2 − ∑ i = 1 n α i ( y i ( w T ⋅ Φ ( x i ) + b ) − 1 ) = 1 2 w T w − w T ∑ i = 1 n α i y i Φ ( x i ) − b ∑ i = 1 n α i y i + ∑ i = 1 n α i = 1 2 w T ∑ i = 1 n α i y i Φ ( x i ) − w T ∑ i = 1 n α i y i Φ ( x i ) − b ⋅ 0 + ∑ i = 1 n α = ∑ i = 1 n α i − 1 2 ( ∑ i = 1 n α i y i Φ ( x i ) ) T ∑ i = 1 n α i y i Φ ( x i ) = ∑ i = 1 n α i − 1 2 ∑ i = 1 n α i α j y i y j Φ T ( x i ) Φ ( x j ) \begin{aligned} L(w, b, \alpha) & = \frac{1}{2} ||w||^2 - \sum_{i=1}^n \alpha_i(y_i(w^T \cdot \Phi(x_i) + b) - 1)\\ & = \frac{1}{2}w^T w - w^T\sum_{i=1}^n\alpha_i y_i \Phi(x_i) - b\sum_{i=1}^n \alpha_i y_i + \sum_{i = 1}^n \alpha_i\\ & = \frac{1}{2}w^T \sum_{i = 1}^n \alpha_i y_i \Phi(x_i) - w^T\sum_{i = 1}^n \alpha_i y_i \Phi(x_i) - b \cdot 0 + \sum_{i=1}^n\alpha\\ & = \sum_{i = 1}^n \alpha_i - \frac{1}{2}\left( \sum_{i=1}^n \alpha_i y_i \Phi(x_i) \right)^T \sum_{i=1}^n \alpha_i y_i \Phi(x_i)\\ & = \sum_{i=1}^n \alpha_i - \frac{1}{2} \sum_{i=1}^n \alpha_i \alpha_j y_i y_j \Phi^T(x_i)\Phi(x_j) \end{aligned} L(w,b,α)=21∣∣w∣∣2−i=1∑nαi(yi(wT⋅Φ(xi)+b)−1)=21wTw−wTi=1∑nαiyiΦ(xi)−bi=1∑nαiyi+i=1∑nαi=21wTi=1∑nαiyiΦ(xi)−wTi=1∑nαiyiΦ(xi)−b⋅0+i=1∑nα=i=1∑nαi−21(i=1∑nαiyiΦ(xi))Ti=1∑nαiyiΦ(xi)=i=1∑nαi−21i=1∑nαiαjyiyjΦT(xi)Φ(xj)
这个对偶函数其实求的是 max α min w , b L ( w , b , α ) \underset{\alpha}{\max} \underset{w, b}{\min} L(w, b, \alpha) αmaxw,bminL(w,b,α) 中的 min L ( w , b ) \min L(w, b) minL(w,b) 部分(因为对 w w w 和 b b b 求了偏导)。于是现在要求的是这个函数的极大值 max ( a ) \max(a) max(a),写成公式就是:
a ∗ = argmax α ( ∑ i = 1 n α i − 1 2 ∑ i = 1 n α i α j y i y j Φ T ( x i ) Φ ( x j ) ) a^* = \underset{\alpha}{\text{argmax}} \left( \sum_{i=1}^n \alpha_i - \frac{1}{2} \sum_{i=1}^n \alpha_i \alpha_j y_i y_j \Phi^T(x_i)\Phi(x_j) \right) a∗=αargmax(i=1∑nαi−21i=1∑nαiαjyiyjΦT(xi)Φ(xj))
好了,现在我们只需要对上式求出极大值 a a a,然后将 a a a 代入 w w w 求偏导的那个公式:
w = ∑ i = 1 n α i y i Φ ( x n ) w = \sum_{i = 1}^n \alpha_i y_i \Phi(x_n) w=i=1∑nαiyiΦ(xn)
从而求出 w w w。再将 w w w 代入超平面的表达式,计算 b b b 值。
现在的 w w w 和 b b b 就是我们要寻找的最优超平面的参数。
我们用数学表达式来说明上面的过程:
第一步:首先是求 min w , b L ( w , b , α ) \underset{w, b}{\min}L(w, b, \alpha) w,bminL(w,b,α) 的极大值,即:
max α ∑ i = 1 n α i − 1 2 ∑ i = 1 n ∑ j = 1 n α i α j y i y j ( Φ T ( x i ) Φ ( x j ) ) s.t. ∑ i = 1 n α i , y i = 0 α i ≥ 0 , i = 1 , 2 , . . . , n \underset{\alpha}{\max}\sum_{i=1}^n \alpha_i - \frac{1}{2} \sum_{i=1}^n \sum_{j=1}^n \alpha_i \alpha_j y_i y_j \left( \Phi^T(x_i)\Phi(x_j) \right)\\ \begin{aligned} \text{s.t.} \quad & \sum_{i=1}^n \alpha_i, y_i = 0\\ & \alpha_i \ge 0, \quad i = 1, 2, ..., n \end{aligned} αmaxi=1∑nαi−21i=1∑nj=1∑nαiαjyiyj(ΦT(xi)Φ(xj))s.t.i=1∑nαi,yi=0αi≥0,i=1,2,...,n
注意有两个约束条件。
对目标函数添加符号,转换成求极小值:
min α 1 2 ∑ i = 1 n ∑ j = 1 n α i α j y i y j ( Φ T ( x i ) Φ ( x j ) ) − ∑ i = 1 n α i s.t. ∑ i = 1 n α i , y i = 0 α i ≥ 0 , i = 1 , 2 , . . . , n \underset{\alpha}{\min}\frac{1}{2} \sum_{i=1}^n\sum_{j=1}^n \alpha_i \alpha_j y_i y_j \left( \Phi^T(x_i)\Phi(x_j) \right) - \sum_{i=1}^n \alpha_i \\ \begin{aligned} \text{s.t.} \quad & \sum_{i=1}^n \alpha_i, y_i = 0\\ & \alpha_i \ge 0, \quad i = 1, 2, ..., n \end{aligned} αmin21i=1∑nj=1∑nαiαjyiyj(ΦT(xi)Φ(xj))−i=1∑nαis.t.i=1∑nαi,yi=0αi≥0,i=1,2,...,n
第二步:计算上面式子的极值求出 α ∗ \alpha^* α∗
第三步:将 α ∗ \alpha^* α∗ 代入,计算 w w w 和 b b b:
w ∗ = ∑ i = 1 n α i ∗ y i Φ ( x i ) b ∗ = y i − ∑ i = 1 n α i ∗ y i ( Φ ( x i ) ⋅ Φ ( x j ) ) \begin{aligned} & w^* = \sum_{i = 1}^n \alpha_i^* y_i \Phi(x_i)\\ & b^* = y_i - \sum_{i = 1}^n \alpha_i^* y_i \left( \Phi(x_i) \cdot \Phi(x_j) \right) \end{aligned} w∗=i=1∑nαi∗yiΦ(xi)b∗=yi−i=1∑nαi∗yi(Φ(xi)⋅Φ(xj))
第四步:求得超平面 w ∗ Φ ( x ) + b ∗ = 0 w^* \Phi(x) + b^* = 0 w∗Φ(x)+b∗=0
第五步:求得分类决策函数 f ( x ) = s i g n ( w ∗ Φ ( x ) + b ∗ ) f(x) = \mathrm{sign}(w^*\Phi(x) + b^*) f(x)=sign(w∗Φ(x)+b∗)
给定 3 个数据点:正例点 x 1 = ( 3 , 3 ) x_1 = (3,3) x1=(3,3), x 2 = ( 4 , 3 ) x_2 = (4, 3) x2=(4,3),负例点 x 3 = ( 1 , 1 ) x_3 = (1, 1) x3=(1,1),求线性可分支持向量机。我们把这三个点画出来:
第一步:首先确定目标函数
求解: 1 2 ∑ i = 1 n ∑ j = 1 n α i α j y i y j ( x i ⋅ x j ) − ∑ i = 1 n α i \frac{1}{2}\sum_{i=1}^n \sum_{j=1}^n \alpha_i \alpha_j y_i y_j(x_i \cdot x_j) - \sum_{i=1}^n \alpha_i 21i=1∑nj=1∑nαiαjyiyj(xi⋅xj)−i=1∑nαi
约束条件: { α 1 + α 2 − α 3 = 0 α i ≥ 0 , i = 1 , 2 , 3 \begin{cases} \alpha_1 + \alpha_2 - \alpha_3 = 0\\ \alpha_i \ge 0, \quad i = 1, 2, 3 \end{cases} {α1+α2−α3=0αi≥0,i=1,2,3
第二步:求得目标函数的极值
其中:
18 = 3 2 + 3 2 25 = 4 2 + 3 2 2 = 1 2 + 1 2 42 = ( 3 × 4 + 3 × 3 ) × 2 12 = ( 3 × 1 + 3 × 1 ) × 2 14 = ( 4 × 1 + 3 × 1 ) × 2 \begin{aligned} & 18 = 3^2 + 3^2\\ & 25 = 4^2 + 3^2\\ & 2 = 1^2 + 1^2\\ & 42 = (3 \times 4 + 3 \times 3) \times 2\\ & 12 = (3 \times 1 + 3 \times 1) \times 2\\ & 14 = (4 \times 1 + 3 \times 1) \times 2\\ \end{aligned} 18=32+3225=42+322=12+1242=(3×4+3×3)×212=(3×1+3×1)×214=(4×1+3×1)×2
由于 α 1 + α 2 = α 3 \alpha_1 + \alpha_2 = \alpha_3 α1+α2=α3,化简可得:
4 α 1 2 + 13 2 α 2 2 + 10 α 1 α 2 − 2 α 1 − 2 α 2 4 \alpha^2_1 + \frac{13}{2}\alpha^2_2 + 10 \alpha_1 \alpha_2 - 2\alpha_1 - 2\alpha_2 4α12+213α22+10α1α2−2α1−2α2
对 α 1 \alpha_1 α1 和 α 2 \alpha_2 α2 求偏导并令其为0可知: s ( α 1 , α 2 ) s(\alpha_1, \alpha_2) s(α1,α2) 在点 ( 1.5 , − 1 ) (1.5, -1) (1.5,−1) 处取极值。但是该点不满足条件 α 2 ≥ 0 \alpha_2 \ge 0 α2≥0(约束条件说了, α i ≥ 0 \alpha_i \ge 0 αi≥0),所以最小值在边界上达到。
因为 s ( 1 4 , 0 ) = − 0.25 < s ( 0 , 2 13 ) = − 0.1538 s(\frac{1}{4}, 0) = -0.25 < s(0, \frac{2}{13}) = -0.1538 s(41,0)=−0.25<s(0,132)=−0.1538,所以 s ( α 1 , α 2 ) s(\alpha_1, \alpha_2) s(α1,α2) 在 α 1 = 1 4 , α 2 = 0 \alpha_1 = \frac{1}{4}, \alpha_2 = 0 α1=41,α2=0 时达到最小,此时:
α 3 = α 1 + α 2 = 1 4 \alpha_3 = \alpha_1 + \alpha_2 = \frac{1}{4} α3=α1+α2=41
第三步:将求得到极值代入,从而求得最优参数 w w w 和 b b b
α 1 = α 3 = 1 4 \alpha_1 = \alpha_3 = \frac{1}{4} α1=α3=41 对应的点 ( x 1 , x 3 ) (x_1, x_3) (x1,x3) 就是支持向量机。
对于公式:
w = ∑ i = 1 n α i y i Φ ( x n ) w = \sum_{i=1}^n \alpha_iy_i\Phi(x_n) w=i=1∑nαiyiΦ(xn)
将 α \alpha α 的结果代入可知:
w = 1 4 × 1 × ( 3 , 3 ) + 1 4 × ( − 1 ) × ( 1 , 1 ) = ( 1 2 , 1 2 ) b = y i − ∑ i = 1 n ∑ j = 1 n α i y i ( x i ⋅ x j ) = 1 − ( 1 4 × 1 × 18 + 1 4 × ( − 1 ) × 6 ) = − 2 \begin{aligned} & w = \frac{1}{4} \times 1 \times (3,3) + \frac{1}{4} \times (-1) \times (1, 1) = (\frac{1}{2}, \frac{1}{2})\\ & b = y_i - \sum_{i=1}^n\sum_{j=1}^n \alpha_i y_i (x_i\cdot x_j) = 1 - (\frac{1}{4} \times 1 \times 18 + \frac{1}{4} \times( -1) \times 6) = -2 \end{aligned} w=41×1×(3,3)+41×(−1)×(1,1)=(21,21)b=yi−i=1∑nj=1∑nαiyi(xi⋅xj)=1−(41×1×18+41×(−1)×6)=−2
因此可知,平面方程为:
0.5 x 1 + 0.5 x 2 − 2 = 0 0.5x_1 + 0.5x_2 - 2 = 0 0.5x1+0.5x2−2=0
第四步:分离超平面
故可知分离超平面为:
0.5 x 1 + 0.5 x 2 − 2 = 0 0.5x_1 + 0.5x_2 - 2 = 0 0.5x1+0.5x2−2=0
第五步:分离决策函数
由于分离超平面可知,故分离决策函数也可知:
f ( x ) = s i g n ( 0.5 x 1 + 0.5 x 2 − 2 ) f(x) = \mathrm{sign}(0.5x_1 + 0.5x_2 - 2) f(x)=sign(0.5x1+0.5x2−2)
另一种计算方式(参考):SVM-求解最大间隔分离超平面
小结:
学习目标:
SVM 之所以这么成功,主要取决于两个因素:
在 SVM 中,我们主要讨论三种损失函数:
Hinge:英[hɪndʒ] 美[hɪndʒ]
n. 铰链; 合叶;
vt. 给(某物)装铰链;
绿色:0/1 损失:
简单来讲,分对了误差为0,分错了误差为1,就是这么绝对,就是这么二极管。
蓝色:SVM Hinge损失函数:
ξ \xi ξ 就是误差
红色:Logistic损失函数
对于支持向量机(SVM),这三种损失函数各有优缺点。
0/1 损失:0/1 损失是一种直观的损失函数,它将分类正确的样本损失设为 0,分类错误的样本损失设为 1。但是,0/1 损失不是连续函数,不利于优化问题的求解。
Hinge 损失函数:Hinge 损失函数是 SVM 中使用的损失函数。它使得 y f ( x ) > 1 yf(x)>1 yf(x)>1 的样本损失皆为 0,由此带来了稀疏解,使得 SVM 仅通过少量的支持向量就能确定最终超平面。
Logistic 损失函数:Logistic 损失函数是逻辑回归中使用的损失函数。它给出了后验概率,但对异常值敏感。
小结:
学习目标:
SVM + 核函数 具有极大威力。
核函数并不是 SVM 特有的,核函数可以和其他算法也进行结合,只是核函数与 SVM 结合的优势非常大。
核函数,是将原始输入空间映射到新的特征空间,从而使得原本线性不可分的样本可能在核空间可分。
上图所示的两类数据,分别分布为两个圆圈的形状(大圆套着小圆),这样的数据本身就是线性不可分的,此时该如何把这两类数据分开呢?
假设 X X X 是输入空间, H H H 是特征空间,存在一个映射 ϕ \phi ϕ 使得 X X X 中的点 x x x 能够计算得到 H H H 空间中的点 h h h,且对于所有的 X X X 中的点都成立。
h = ϕ ( x ) h = \phi(x) h=ϕ(x)
若 x x x和 z z z 是 X X X 空间中的点,函数 k ( x , z ) k(x,z) k(x,z) 满足下述条件:
k ( x , z ) = ϕ ( x ) ⋅ ϕ ( z ) k(x, z) = \phi(x) \cdot \phi(z) k(x,z)=ϕ(x)⋅ϕ(z)
如果都成立,则称函数 k k k 为核函数,而 ϕ \phi ϕ 为映射函数。
ϕ : R 2 → R 3 ( x 1 , x 2 ) → ( z 1 , z 2 , z 3 ) = ( x 1 2 , 2 x 1 x 2 , x 2 2 ) \begin{aligned} & \phi: R^2 \rightarrow R^3\\ & (x_1, x_2) \rightarrow (z_1, z_2, z_3) = (x^2_1, \sqrt{2}x_1x_2, x_2^2) \end{aligned} ϕ:R2→R3(x1,x2)→(z1,z2,z3)=(x12,2x1x2,x22)
< ϕ ( x 1 , x 2 ) ϕ ( x 1 ′ , x 2 ′ ) > = < ( z 1 , z 2 , z 3 ) ( z 1 ′ , z 2 ′ , z 3 ′ ) > = < ( x 1 2 , 2 x 1 x 2 , x 2 2 ) ( x 1 ′ 2 , 2 x 1 ′ x 2 ′ , x 2 ′ 2 ) > = x 1 2 x 1 ′ 2 + 2 x 1 x 2 x 1 ′ x 2 ′ + x 2 2 x 2 ′ 2 = ( x 1 x 1 ′ + x 2 x 2 ′ ) 2 = ( < x , x ′ > ) 2 = K ( x , x ′ ) \begin{aligned} \left< \phi(x_1, x_2) \phi(x'_1, x'_2) \right> & = \left< (z_1, z_2, z_3)(z'_1, z'_2, z'_3) \right> \\ & = \left< (x_1^2, \sqrt{2}x_1x_2, x_2^2)(x'^2_1, \sqrt{2}x'_1x'_2, x'^2_2) \right>\\ & = x_1^2x'^2_1 + 2x_1x_2x'_1x'_2 + x^2_2x'^2_2\\ & = (x_1x'_1 + x_2x'_2)^2\\ & = (\left< x, x' \right>)^2\\ & = \mathcal{K}(x, x') \end{aligned} ⟨ϕ(x1,x2)ϕ(x1′,x2′)⟩=⟨(z1,z2,z3)(z1′,z2′,z3′)⟩=⟨(x12,2x1x2,x22)(x1′2,2x1′x2′,x2′2)⟩=x12x1′2+2x1x2x1′x2′+x22x2′2=(x1x1′+x2x2′)2=(⟨x,x′⟩)2=K(x,x′)
经过上面公式,具体变换过过程为:
x = ( x 1 , x 2 , x 3 ) = ( 1 , 2 , 3 ) y = ( y 1 , y 2 , y 3 ) = ( 4 , 5 , 6 ) f ( x ) = ( x 1 x 1 , x 1 x 2 , x 1 x 3 , x 2 x 1 , x 2 x 2 , x 2 x 3 , x 3 x 1 , x 3 x 2 , x 3 x 3 ) f ( x ) = ( 1 , 2 , 3 , 2 , 4 , 6 , 3 , 6 , 9 ) f ( y ) = ( 16 , 20 , 24 , 20 , 25 , 36 , 24 , 30 , 36 ) < f ( x ) , f ( y ) > = 16 + 40 + 72 + 40 + 100 + 180 + 72 + 180 + 324 = 1024 K ( x , y ) = ( < z , y > ) 2 − < f ( x ) , f ( y ) > = ( 4 + 10 + 18 ) 2 − 3 2 2 = 1024 \begin{aligned} & x = (x_1,x_2,x_3) = (1,2,3)\\ & y = (y_1, y_2, y_3)= (4,5,6)\\ & f(x) = (x_1x_1, x_1x_2, x_1x_3, x_2x_1, x_2x_2, x_2x_3, x_3x_1, x_3x_2, x_3x_3)\\ & f(x) = (1,2,3,2,4,6,3,6,9)\\ & f(y) = (16,20,24,20,25, 36, 24, 30, 36)\\ & \left< f(x),f(y) \right> = 16 + 40 + 72 + 40 + 100 + 180 + 72 + 180 + 324 = 1024\\ & \mathcal{K}(x, y) = (\left< z,y \right>)^2 - \left< f(x),f(y) \right> =(4 + 10 + 18)^2- 32^2 = 1024 \end{aligned} x=(x1,x2,x3)=(1,2,3)y=(y1,y2,y3)=(4,5,6)f(x)=(x1x1,x1x2,x1x3,x2x1,x2x2,x2x3,x3x1,x3x2,x3x3)f(x)=(1,2,3,2,4,6,3,6,9)f(y)=(16,20,24,20,25,36,24,30,36)⟨f(x),f(y)⟩=16+40+72+40+100+180+72+180+324=1024K(x,y)=(⟨z,y⟩)2−⟨f(x),f(y)⟩=(4+10+18)2−322=1024
下面这张图位于第一、二象限内。我们关注红色的门,以及“北京四合院”这几个字和下面的紫色的字母。
我们把红色的门上的点看成是“+”数据,字母上的点看成是“-”数据,它们的横、纵坐标是两个特征。显然,在这个二维空间内,“+”和“-”两类数据不是线性可分的。
简单来说,黑色和红色不是线性可分的。
如上图所示,将二维数据映射到三维空间后,可以使用绿色的平面完美地分割 红色 和 紫色,因此二维数据在三维空间中变成线性可分的了。
前后轴为 x x x 轴,左右轴为 y y y 轴,上下轴为 z z z 轴
将切分回到二维平面,如下图所示。
我们可以看到,三维空间中判决边界再映射回二维空间后,并不是一条直线,而是是一条双曲线,它不是线性的。
通过上述的例子我们可以知道,核函数的作用就是一个从低维空间到高维空间的映射,而这个映射可以把低维空间中线性不可分的两类点变成线性可分的。
名称 | 表达式 | 参数 |
---|---|---|
线性核 | K ( x i , x j ) = x i T x j \mathcal{K}(x_i, x_j) = x_i^Tx_j K(xi,xj)=xiTxj | x i x_i xi 和 x j x_j xj 为输入向量,表示数据集中的两个样本 |
多项式核 | K ( x i , x j ) = ( x i T x j ) d \mathcal{K}(x_i, x_j) = (x_i^Tx_j)^d K(xi,xj)=(xiTxj)d | d ≥ 1 d\ge 1 d≥1 为多项式的次数 |
高斯核 | K ( x i , x j ) = exp ( − ∣ x i − x j ∣ 2 2 σ 2 ) \mathcal{K}(x_i, x_j) = \exp\left( -\frac{|x_i - x_j|^2}{2\sigma^2} \right) K(xi,xj)=exp(−2σ2∣xi−xj∣2) | σ > 0 \sigma > 0 σ>0 为高斯核的带宽(width), ∣ x i − x j ∣ |x_i - x_j| ∣xi−xj∣ 表示 x i x_i xi 和 x j x_j xj 之间的欧几里得距离 |
拉普拉斯核 | K ( x i , x j ) = exp ( − ∣ x i − x j ∣ σ ) \mathcal{K}(x_i, x_j) = \exp\left( -\frac{|x_i - x_j|}{\sigma} \right) K(xi,xj)=exp(−σ∣xi−xj∣) | σ > 0 \sigma > 0 σ>0,控制了核函数的宽度 |
Sigmoid 核 | K ( x i , x j ) = tanh ( β x i T x j + θ ) \mathcal{K}(x_i, x_j) = \tanh(\beta x_i^Tx_j + \theta) K(xi,xj)=tanh(βxiTxj+θ) | tanh \tanh tanh 为双曲正切函数, β > 0 \beta > 0 β>0, θ < 0 \theta < 0 θ<0。 β \beta β 是一个缩放因子,它控制了输入向量 x i T x j x_i^Tx_j xiTxj 的缩放程度; θ \theta θ 是一个常数偏置项,它控制了双曲正切函数的水平位移 |
- 多项核中,当 d = 1 d=1 d=1 时,退化为线性核
- 高斯核亦称为 RBF 核(Radial Basis Function,径向基函数)。
核函数选择的指导规则:
我们一般优先使用 RBF 高斯核进行计算
Q:高斯核为什么叫做 RBF 核?
A:RBF 是 Radial Basis Function(径向基函数)的缩写。径向基函数是一类以原点为中心,对称于原点的函数。它们通常用来描述以某个点为中心,向外扩散的过程。高斯核函数是一种常用的径向基函数,它的表达式为 K ( x i , x j ) = exp ( − ∥ x i − x j ∥ 2 2 σ 2 ) \mathcal{K}(x_i, x_j) = \exp\left( -\frac{\|x_i - x_j\|^2}{2\sigma^2} \right) K(xi,xj)=exp(−2σ2∥xi−xj∥2),其中 σ > 0 \sigma > 0 σ>0 是高斯核的带宽(width), ∥ x i − x j ∥ \|x_i - x_j\| ∥xi−xj∥ 表示 x i x_i xi 和 x j x_j xj 之间的欧几里得距离。由于高斯核函数是一种径向基函数,因此它也被称为 RBF 核。
小结:
学习目标:
SVM 回归与 SVM 的分类有一些区别。SVM 的回归是让尽可能多的实例位于预测线上,同时限制间隔违例(也就是不在预测线距上的实例)。
线距的宽度由超参数 ϵ \epsilon ϵ 控制。
SVM 的目的是让图中的点在线上就可以。SVM 本身是有一个最大间隔的(不管是回归还是分类,这个最大间隔都是存在的),这个最大间隔通过 ϵ \epsilon ϵ 决定:
要想让 SVM 实现回归,API 应该使用 SVR
(之前分类用的是 SVC
),具体的 API 接下来会讲到。
学习目标:
SVM 方法既可以用于分类(二/多 分类),也可用于回归和异常值检测。
SVM 具有良好的鲁棒性,对未知数据拥有很强的泛化能力,特别是在数据量较少的情况下,相较其他传统机器学习算法具有更优的性能。
使用 SVM 作为模型时,通常采用如下流程:
sklearn 中支持向量分类主要有三种方法:SVC、NuSVC、LinearSVC,扩展为三个支持向量回归方法:
nu
参数和 SVC 中的 C
参数kernel
参数class sklearn.svm.SVC(C=1.0,kernel='rbf', degree=3, coef0=0.0, random_state=None)
sklearn.svm.SVC
是 scikit-learn 库中的一个类,用于进行 C-支持向量分类。它基于 libsvm 实现,拟合时间至少与样本数量的平方成正比,对于超过数万个样本的大型数据集可能不切实际。对于大型数据集,可以考虑使用 LinearSVC 或 SGDClassifier,也可以在使用 Nystroem 变换器或其他核近似之后使用。C
:正则化参数(惩罚系数)。用来控制损失函数的惩罚系数,类似于线性回归中的正则化系数。正则化强度与 C 成反比。必须严格为正。惩罚是平方 l2 惩罚。
C
越大,相当于惩罚松弛变量,希望松弛变量接近0,即对误分类的惩罚增大,趋向于对训练集全分对的情况,这样会出现训练集测试时准确率很高,但泛化能力弱,容易导致过拟合。C
值小,对误分类的惩罚减小,容错能力增强,泛化能力较强,但也可能欠拟合。kernel
:算法中采用的核函数类型,核函数是用来将非线性问题转化为线性问题的一种方法。
degree
:多项式内核函数(“poly”)的次数。
coef0
:内核函数中的独立项,即 y = k x + b y=kx+b y=kx+b 中的 b b b 值。
random_state
:控制伪随机数生成以进行混洗和概率估计时使用的交叉验证。传递一个 int 以获得可重复的输出。fit
predict
score
等class sklearn.svm.NuSVC(nu=0.5)
作用:sklearn.svm.NuSVC
是 scikit-learn 库中的一个类,用于进行 Nu-支持向量分类。它与 SVC 类似,但使用一个参数来控制支持向量的数量。它基于 libsvm 实现。
参数说明:
nu
:边界误差的上限和支持向量分数的下限(训练误差部分的上限和支持向量部分的下限)。应在区间 ( 0 , 1 ] (0, 1] (0,1] 内,默认是 0.5。kernel
:指定算法中要使用的内核类型。如果没有给出,则将使用“rbf”。如果给定了可调用对象,则用它来预先计算内核矩阵。degree
:多项式内核函数(“poly”)的次数。必须为非负数。所有其他内核都忽略它。coef0
:内核函数中的独立项。仅在“poly”和“sigmoid”中有意义。random_state
:控制伪随机数生成以进行混洗和概率估计时使用的交叉验证。传递一个 int 以获得可重复的输出。方法:
fit
predict
score
等NuSVC 和 SVC 的唯一区别就是多了一个参数 Nu,即 ν \nu ν。
class sklearn.svm.LinearSVC(penalty='l2', loss='squared_hinge', dual=True, C=1.0)
作用:sklearn.svm.LinearSVC
是 scikit-learn 库中的一个类,用于进行线性支持向量分类。它与参数 kernel='linear'
的 SVC 类似,但是以 liblinear 而不是 libsvm 的形式实现,因此它在惩罚和损失函数的选择方面具有更大的灵活性,并且应该更好地扩展到大量样本。该类支持密集和稀疏输入,多类支持根据一对多方案进行处理。
参数说明:
penalty
:指定用于惩罚的范数。
penalty
参数是 线性 SVC 独有的loss
:指定损失函数。有 “hinge” 和 “squared_hinge” 两种可选:
dual
:是否转化为对偶问题求解,默认是True。
C
:正则化参数。用来控制损失函数的惩罚系数,类似于线性回归中的正则化系数。正则化强度与 C 成反比。必须严格为正。方法:
fit
predict
score
等三种 SVC 中用的最多的就是 SVC(原始的SVC)。
小结:
sklearn.svm.SVC
sklearn.svm.NuSVC
sklearn.svm.LinearSVC
学习目标:
数据集下载地址:Digit Recognizer
MNIST(“修改后的国家标准与技术研究所”)是计算机视觉事实上的 “hello world” 数据集。自 1999 年发布以来,这一经典的手写图像数据集已成为分类算法基准测试的基础。随着新的机器学习技术的出现,MNIST 仍然是研究人员和学习者的可靠资源。
MNIST 是 Modified National Institute of Standards and Technology database 的缩写。它是一个大型手写数字数据库,常用于训练各种图像处理系统。该数据库也广泛用于机器学习领域的训练和测试。
本次案例中,我们的目标是从数万个手写图像的数据集中正确识别数字。
数据文件 train.csv
和 test.csv
包含从 0 到 9 的手绘数字的灰度图像。每个图像的高度为 28 个像素,宽度为 28 个像素,总共为 784 个像素(正方形)。
每个像素具有与其相关联的单个像素值,指示该像素的亮度或暗度,较高的数字意味着较亮。该像素值是 0 到 255 之间的整数(包括 0 和 255)。
训练数据集(train.csv
)有 785 列。第一列称为“标签”,是用户绘制的数字。其余列包含关联图像的像素值。
训练集中的每个像素列都具有像 p i x e l x \mathrm{pixel}_x pixelx 这样的名称,其中 x x x 是 0 到 783 之间的整数(包括 0 和 783)。为了在图像上定位该像素,假设我们已经将 x x x 分解为 x = i × 28 + j x = i \times 28 + j x=i×28+j,其中 i i i 和 j j j 是 0 到 27 之间的整数(包括 0 和27)。然后, p i x e l x \mathrm{pixel}_x pixelx 位于 28 × 28 28 \times 28 28×28 矩阵的第 i i i 行和第 j j j 列上(索引为0)。
例如, p i x e l 31 \mathrm{pixel}_{31} pixel31 表示从左边开始的第 4 列中的像素,以及从顶部开始的第 2 行,如下面的 ASCII 图中所示。在视觉上,如果我们省略“像素(pixel)”的前缀,像素组成图像如下:
000 001 002 003 ... 026 027
028 029 030 031 ... 054 055
056 057 058 059 ... 082 083
| | | | ... | |
728 729 730 731 ... 754 755
756 757 758 759 ... 782 783
测试数据集(test.csv
)与训练集相同,只是它不包含“标签”列。
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
# 1. 获取数据
train = pd.read_csv("./data/digit-recognizer/train.csv")
print(train.shape) # (42000, 785)
train.head()
我们可以看到,MNIST 数据集中,训练集的样本数量很多,且特征数也很多,这么多的特征数是不利于模型训练的,此时我们可以对其进行降维。
从上图可以看到,特征值和目标值是在一起的,所以我们需要将其进行分离:
# 获取图片数据
train_image = train.iloc[:, 1:]
train_image.head()
# 获取目标值
train_label = train.iloc[:, :1]
train_label.head()
我们可以查看一下具体的图像:
# 查看一下具体的图像
train_exp = train_image.iloc[0, :]
print(train_exp)
"""
pixel0 0
pixel1 0
pixel2 0
pixel3 0
pixel4 0
..
pixel779 0
pixel780 0
pixel781 0
pixel782 0
pixel783 0
Name: 0, Length: 784, dtype: int64
"""
# 我们发现此时还是带着index列的,我们将其去除一下
train_exp = train_exp.values
print(train_exp)
"""
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 188 255 94 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 191 250 253
93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 123 248 253 167 10 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 247 253
208 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 29 207 253 235 77 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 54 209 253
253 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 93 254 253 238 170 17 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 210 254
253 159 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 16 209 253 254 240 81 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 253
253 254 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 20 206 254 254 198 7 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 168
253 253 196 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 20 203 253 248 76 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22
188 253 245 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 103 253 253 191 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
89 240 253 195 25 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 15 220 253 253 80 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 94 253 253 253 94 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 89 251 253 250 131 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 214 218 95 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0]
"""
# 此时我们仍然看不出来到底是怎样的数字(主要是print函数打印不下了,其实是可以看出来的),我们画一下就清晰明了了
train_exp = train_exp.reshape(28, 28)
plt.figure(dpi=100)
plt.imshow(train_exp)
plt.axis("off") # 关闭轴
plt.show()
为了能够更加方便的展示数据,我们写一个函数:
def show_digit(n):
"""
n:展示第n张图片
"""
show_img = train_image.iloc[n, :].values.reshape(28, 28)
plt.figure(dpi=100)
plt.imshow(show_img)
plt.axis("off") # 关闭轴
plt.show()
show_digit(50)
因为灰度图的取值范围是 [ 0 , 255 ] [0, 255] [0,255],落差太大了,不利于模型的训练,因此我们需要对其进行归一化处理。归一化的方式也很简单,直接除以 255 即可。
# 2. 数据基本处理
# 对数据特征值进行归一化
train_image = train_image.values / 255 # 这样处理后,就没有第一列了
print("数据最大值为:", np.max(train_image))
train_image
数据最大值为:1.0
array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]])
我们还需要对目标值进行处理,现在的目标值是带有索引列的,这个索引列我们是不需要的。
train_label = train_label.values
train_label
array([[1],
[0],
[1],
...,
[7],
[6],
[9]], dtype=int64)
接下来我们需要对数据集进行划分,分为训练集和测试集(因为 MNIST 的测试集没有 Ground Truth,因此我们只使用训练集):
x_train, x_test, y_train, y_test = train_test_split(train_image, train_label, train_size=0.8, random_state=0)
print("x_train.shape:", x_train.shape)
print("x_test.shape:", x_test.shape)
print("y_train.shape:", y_train.shape)
print("y_test.shape:", y_test.shape)
x_train.shape: (33600, 784)
x_test.shape: (8400, 784)
y_train.shape: (33600, 1)
y_test.shape: (8400, 1)
从上面数据的 shape 可以看到,784 个特征还是太大了,所以我们需要对其进行降维。可以考虑对数据进行降维,原因有以下几点:
计算效率:当数据维度很高时,计算量会很大,这会导致模型训练和预测速度变慢。通过降维,可以减少计算量,提高计算效率。
去除冗余信息:原始数据中可能存在冗余信息或噪声,这些信息对模型的预测能力没有帮助,甚至会影响模型的性能。通过降维,可以去除这些冗余信息,提高模型的预测能力。
可视化:当数据维度很高时,很难直观地观察数据的分布情况。通过降维,可以将高维数据映射到二维或三维空间中,方便进行可视化。
常用的降维方法有主成分分析(PCA)、线性判别分析(LDA)等。
思路:通过多次使用 PCA 确定最优模型。
# 3. 特征降维和模型训练
import time
from sklearn.decomposition import PCA
def n_components_analysis(n, x_train, y_train, x_test, y_test):
"""
思路:通过多次使用 PCA 确定最优模型
参数说明:
n: 降维后的目标维度(可以是整数也可以是小数)
整数:具体降到多少维
小数:表示保留百分之多少的信息
x_train:训练集数据
y_train:训练集标签
x_test:测试集数据
y_test:测试集标签
"""
# 记录开始时间
start_tm = time.time()
# PCA降维实现
pca = PCA(n_components=n) # Python中会区分大小写
print("特征降维传递的参数为:{}".format(n))
# 学习如何降维
pca.fit(x_train)
# 在训练集和测试集进行降维
x_train_pca = pca.transform(x_train)
x_test_pca = pca.transform(x_test)
"""
`pca.fit(x_train)` 是用来训练 PCA 模型的。它会根据训练数据 `x_train` 来计算降维所需的参数,如主成分和方差解释度等。
`pca.transform` 是用来对数据进行降维的。它会根据训练好的 PCA 模型,将原始数据映射到低维空间中。
例如,如果我们希望将原始数据降维到 100 维,则可以使用 `pca.transform(x_train)` 将训练数据降维到 100 维,
使用 `pca.transform(x_test)` 将测试数据降维到 100 维。
需要注意的是,在对测试数据进行降维时,应该使用与训练数据相同的 PCA 模型,即使用相同的主成分和方差解释度等参数。
"""
# 利用 SVM 进行模型训练(这里使用常见的svc)
svc = svm.SVC()
print("开始使用SVC进行训练")
"""
svc.fit 函数期望接收一个一维数组作为标签,而不是一个列向量。
因此我们需要借助 .ravel()方法 将多维数组展平为一维数组。
例如,如果 y_train 是一个形状为 (n_samples, 1) 的列向量,
则 y_train.ravel() 会返回一个形状为 (n_samples,) 的一维数组。
"""
svc.fit(x_train_pca, y_train.ravel())
# 获取accuracy结果
acc = svc.score(x_test_pca, y_test)
# 记录结束时间
end_tm = time.time()
print(f"[n_components={n}]准确率为:{acc * 100:.4f}%,耗时{end_tm - start_tm:.2f}s\r\n")
return acc
# 传递多个 n_components 参数以寻找合理的降维数和 SVM 模型(注意这里是“合理的”而不是“最优的”)
n_lst = np.linspace(0.70, 0.85, num=5)
acc_lst = []
for n in n_lst:
acc = n_components_analysis(n, x_train, y_train, x_test, y_test)
acc_lst.append(acc)
print("\r\nacc_lst:", acc_lst)
特征降维传递的参数为:0.7
开始使用SVC进行训练
[n_components=0.7]准确率为:97.6190%,耗时15.19s
特征降维传递的参数为:0.7374999999999999
开始使用SVC进行训练
[n_components=0.7374999999999999]准确率为:97.7976%,耗时16.66s
特征降维传递的参数为:0.7749999999999999
开始使用SVC进行训练
[n_components=0.7749999999999999]准确率为:97.8333%,耗时16.80s
特征降维传递的参数为:0.8125
开始使用SVC进行训练
[n_components=0.8125]准确率为:97.9881%,耗时19.69s
特征降维传递的参数为:0.85
开始使用SVC进行训练
[n_components=0.85]准确率为:98.0357%,耗时22.84s
acc_lst: [0.9761904761904762, 0.9779761904761904, 0.9783333333333334, 0.9798809523809524, 0.9803571428571428]
思考:我们可以看到,随着保留特征的增加,模型的准确率会逐渐上升,这是一个好现象吗?
我们很明显的看到,随着保留特征数的增加,训练时间也在增加。而且我们要记得,这个准确率是训练集准确率,而训练集准确率的提升并不意味着模型就在变好,因为可能会发生过拟合!
这也就解释了为什么我们说要找一个“合理的”
n_component
,而不是找“最优的”的n_component
。
干巴巴的数字总是枯燥且抽象的,所以我们对训练集准确率进行可视化展示:
# 训练集准确率可视化展示
plt.figure(dpi=300)
plt.plot(n_lst, acc_lst, 'r')
plt.scatter(n_lst, acc_lst)
plt.show()
经过图像展示,选择合理的 n_component
。综合考虑,我们选择 n_component=0.80
。
# 4. 确定最优模型
pca = PCA(n_components=0.80)
# 训练pca
pca.fit(x_train)
print("经过PCA降维后,数据的特征数为:", pca.n_components_)
经过PCA降维后,数据的特征数为: 43
我们可以看到,大量的特征被剔除,只剩下 43 个特征被保留。
接下来我们对数据应用 PCA 降维:
x_train_pca = pca.transform(x_train)
x_test_pca = pca.transform(x_test)
print("经过PCA降维后,训练集shape为:", x_train_pca.shape)
print("经过PCA降维后,测试集shape为:", x_test_pca.shape)
经过PCA降维后,训练集shape为: (33600, 43)
经过PCA降维后,测试集shape为: (8400, 43)
接下来我们可以训练选择出来的最优模型:
# 训练最优模型
svc = svm.SVC()
svc.fit(x_train_pca, y_train.ravel())
acc = svc.score(x_test_pca, y_test)
print(f"最优模型的准确率为:{acc*100:.4f}%")
最优模型的准确率为:97.9048%
SVM是一种二类分类模型。
SVM 也可以用于 多分类 和 回归 问题上!只不过二分类是 SVM 最擅长的问题。
它的基本模型是在特征空间中寻找 间隔最大化的分离超平面的线性分类器。
维度灾难是指当数据维度增加时,数据的分布会变得稀疏,这会导致模型的预测能力下降。为了解决这个问题,可以考虑使用降维技术来减少数据的维度。
需要注意的是,维度灾难并不仅仅发生在特征数比样本数大的情况下,它也可能发生在特征数较大但样本数充足的情况下。
Q:什么是 ∣ ∣ w ∣ ∣ ||w|| ∣∣w∣∣?
A: ∣ ∣ w ∣ ∣ ||w|| ∣∣w∣∣ 就是求向量 w w w 的 2-范数。
范数是一种度量向量大小的函数,它满足一些特定的性质,如非负性、齐次性、三角不等式等。
常见的范数有 1-范数、2-范数和无穷范数。对于一个向量 w = ( w 1 , w 2 , . . . , w n ) w = (w_1, w_2, ..., w_n) w=(w1,w2,...,wn),它们分别定义为:
当未指定具体的范数类型时, ∣ ∣ w ∣ ∣ ||w|| ∣∣w∣∣ 默认表示向量 w w w 的 2-范数。
例子:向量 X = [ 2 , 3 , − 5 , − 7 ] X=[2,3, -5, -7] X=[2,3,−5,−7],求向量的 1-范数,2-范数和无穷范数。
例子:矩阵 A A A为:
A = [ 2 3 − 5 − 7 4 6 8 − 4 6 − 11 − 3 16 ] A = \begin{bmatrix} 2 & 3 & -5 & -7\\ 4 & 6 & 8 & -4\\ 6 & -11 & -3 & 16 \end{bmatrix} A= 24636−11−58−3−7−416
求矩阵 A A A 的 1-范数,2-范数和无穷范数。
矩阵的 2-范数定义为矩阵的最大奇异值。计算奇异值需要进行奇异值分解,这一过程比较复杂,无法手动计算。可以使用计算软件(如 MATLAB 或 NumPy)来计算矩阵的奇异值。在 NumPy 中,您可以这样做:
import numpy as np
A = np.array([[2, 3, -5, -7], [4, 6, 8, -4], [6, -11, -3, 16]])
u, s, vh = np.linalg.svd(A)
norm_2 = s[0]
print("矩阵 A 的 2-范数为:", norm_2)
矩阵 A 的 2-范数为: 22.44432815341996
原文链接:向量与矩阵的范数(比较1-范数、2-范数、无穷范数、p-范数、L0范数 和 L1范数等)
拉格朗日乘子法(Lagrange multipliers)是一种寻找多元函数在一组约束下的极值的方法。通过引入拉格朗日乘子,可将有 d d d 个变量与 k k k 个约束条件的最优化问题转化为具有 d + k d + k d+k 个变量的无约束优化问题求解。
以包含 1 个变量 1 个约束的简单优化问题为例。
min x f ( x ) = x 2 + 4 x − 1 (1)s.t. x + 1 ≤ 0 (2)s.t. − x − 1 ≤ 0 \underset{x}{\min}f(x) = x^2 + 4x - 1 \\ \text{(1)s.t.} \quad x+1 \le 0\\ \text{(2)s.t.} \quad -x-1 \le 0\\ xminf(x)=x2+4x−1(1)s.t.x+1≤0(2)s.t.−x−1≤0
它的图像如下:
如图所示,我们的目标函数是: f ( x ) = x 2 + 4 x − 1 f(x) = x^2 + 4x - 1 f(x)=x2+4x−1,讨论两种约束条件 g ( x ) g(x) g(x):
我们可以直观地从图中得到:
上面是通过看图得到的,下面我们用拉格朗日乘子来求解这个最优解。
当没有约束的时候,我们可以直接令目标函数的导数为0,求最优值(这是我们最常用的一种方式)。
可现在有约束,那怎么一边考虑约束一边求目标函数最优值呢?
最直观的办法是把约束放进目标函数里。由于本例中只有一个约束,所以引入一个朗格朗日乘子 λ \lambda λ,构造一个新的函数,即拉格朗日函数 h ( x ) h(x) h(x),如下所示:
h ( x ) = f ( x ) + λ g ( x ) h(x)= f(x) + \lambda g(x) h(x)=f(x)+λg(x)
该拉格朗日函数 h ( x ) h(x) h(x) 最优解可能在 g ( x ) < 0 g(x)<0 g(x)<0 区域中,或者在边界 g ( x ) = 0 g(x)=0 g(x)=0 上,下面具体分析这两种情况:
其中: