1、理论
1.1 间隔与间隔最大化
给定训练样本样本集D={(X1,y1),(X2,y2), (X3,y3),…,(Xm,ym)},其中yi{-1, +1}。
对于一个二分类问题,我们的基本思想是基于训练集D在样本空间中找到一个划分超平面,将不同类别的样本分开。但是如下所示:
图1 存在多个超平面将二分类问题数据进行分开
能将训练样本分开的超平面有很多,哪一个是最好的呢?
由于我们的训练集的局限性和噪声影响,训练集外的样本可能更接近两个类的分隔,这将使许多超平面出现错误,所以最好的分离超平面应该是处于"正中间"的划分超平面,这时的分离超平面是最鲁棒的。
(1) 超平面
在样本空间中,划分超平面的通过如下方程表示:
其中= (1, 2,3,…,n)为法向量,决定超平面的方向;
b为位移项,决定超平面和原点之间的距离。
(2) 函数间隔和几何间隔
一般来说,一个点距离分离超平面的远近可以表示分类预测的确信程度。在超平面 确定的情况下,|| 能够相对的表示点x距离超平面的远近。并且 的符号与类标记y的符号能否一致能够表示分类是否正确。
所以最后我们可以用 来度量分类的正确性和确信度,即函数间隔。
其中定义超平面 关于训练集D的函数间隔为超平面 关于D中所有样本点的函数间隔中最小值,即:
函数间隔可以表示分类预测的正确性及确信度,但是选择分离超平面时候,只有函数间隔是不够的。因为只要成比例的改变 和 ,超平面并不会发生改变,但是间隔也成比例的改变了,不能准确的表示确信度。所以我们下面要对函数间隔进行归一化,即几何间隔。
其中,||||为的范数。其中定义超平面 关于训练集D的几何间隔为超平面 关于D中所有样本点的函数间隔中最小值,即:
所以一般地,当样本点被超平面正确分类时,点与超平面的几何距离是:。
(3) 间隔最大化
支持向量机学习的基本想法是求解能够正确划分训练数据集并且几何间距最大的分离超平面。
对线性可分的训练数据集而言,线性可分分离超平面有无穷多个,但是几何间距最大的分离超平面是唯一的。这里的间隔最大化又称为硬间隔最大化。(与将要讨论的训练数据集近似线性可分时的软间隔最大化相对应)
间隔最大化的直观解释是:对训练数据集找到几何间隔最大的超平面意味着以充分的确信度对训练数据进行分类。即找到支持向量对应的几何距离即可。
假设超平面(, )能将训练样本正确分开,即对应(,),若,则有;若有,则有。其中支持向量表示为:。两个异类支持向量到超平面的距离为:
此时欲找到"最大间隔"的划分超平面,即满足:
等价于:
这是一个凸二次规划问题。
1.2 拉格朗日对偶问题
为了求解线性可分支持向量机的最优化问题,将它作为原始最优化问题,应用拉格朗日对偶性,通过求解对偶问题得到原始问题的最优解。
(1) 拉格朗日对偶函数
我们的原始问题为:
我们将这个问题一般化:
首先构建拉格朗日函数。为此,对每一个不等式约束,引进拉格朗日乘子 和 ,定义拉格朗日函数为:
其中我们令:
这个函数 对于满足原始问题约束条件的那些 来说,其值等于 。因为满足约束条件的 会使得 ,因此最后一项消掉了,而 ,并且我们要求了 ,因此 ,所以最大值只能在它们都取零的时候得到,这个时候就只剩下 了。因此,对于满足约束条件的那些 来说, 。这样一来,原始的带约束的优化问题其实等价于如下的无约束优化问题:
我们把上述式子称为原始问题的,下面等式为原始问题的对偶问题:
(2) KKT条件推导
求解上面的对偶问题,我们同样可以使用等式约束条件的求解思路,对所有的参数进行求导,但是对于求解出的最优解,必须满足KKT条件 (Karush-Kuhn-Tucker)。
我们令:
求解析式可先将 看成是关于 的函数,而将拉格朗日乘子看作常数,求出 的极小值点,再将该点代入 ,得到的关于 和 的表达式就是对偶函数。
对偶函数具有如下两条重要性质:
i. 对偶函数一定是凹函数,其凹性与原目标函数和约束函数凹凸与否无关。
ii. 对 (泛指向量中的每个分量),如果原问题最优解对应的目标函数值为 ,则 。
1 slater条件
,对偶函数 是原问题最优值 的一个下界,最好的下界就是最大化对偶函数,因此构造原问题的对偶问题:式(13)和式(14)。
由于对偶函数是凹函数,故拉格朗日对偶问题一定是凸优化问题,其对应的最优解为 (最优拉格朗日乘子),若对应的最优值为 ,则总有。
其中:
1、当 时,称为弱对偶(weak duality)。
2、当 。
3、将
注:在解存在的情况下,弱对偶总是成立的。满足强对偶时,可以通过求解对偶问题来得到原始问题的解。
Slater 条件用于判断什么情况下强对偶是成立的。在原问题是凸问题的情况下,若 ,使得约束条件满足:
则强对偶成立。
其中 表示原始凸问题定义域的相对内部,即在定义域上除了边界点以外的所有点。只要能找到一个这样的点使原凸问题等式约束依然成立且不等式约束都严格小于 即可。对大多数一般的原凸问题,强对偶都是成立的。
2 KKT条件
如果原始问题是一个凸优化问题,且存在 和 满足 KKT 条件,那么它们分别是 原始问题 和 对偶问题 的极值点并且强对偶性成立。(因为SVM是一个凸二次规划问题,且满足KKT条件,所以可以用对偶问题进行解决。)
1.3 求解对偶问题
其中:
所以,为了得到对偶问题的解,需要先求对 的极小,然后再求对的极小。
(1) 求
分别对求偏导数并令其等于0。
最后得:
将式(19)代入式(18),并利用式(20),即得:
即:
(2) 求对的极大,即是对偶问题:
考虑原始最优化问题和对偶最优化问题,原始问题满足强对偶条件,所以存在,使是原始问题的解,是对偶问题的解。
对线性可分训练数据集,假设对偶最优化问题对的解为。
根据KKT条件,有:
由此得:
其中至少有一个(用反证法,假设,由上式可得,而不是原始最优化问题的解,产生矛盾),对此有:
将式24代入式25中,且注意到可得:
最后根据式24和式26可得,分离超平面可以写成:
分类决策函数可以写成:
我们可以得知,分类决策函数只依赖于输入和训练样本输入的内积。
2、实践
# 导入numpy
import numpy as np
# 导入画图工具
import matplotlib.pyplot as plt
# 导入支持向量机svm
from sklearn import svm
# 导入数据集生成工具
from sklearn.datasets import make_blobs
# 先创建50个数据点,让他们分为两类
X, y = make_blobs(n_samples=50, centers=2, random_state=6)
# 创建一个线性内核的支持向量机模型
clf = svm.SVC(kernel='linear', C=1000)
clf.fit(X, y)
# 把数据点画出来
plt.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=plt.cm.Paired)
# 建立图像坐标
ax = plt.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
# 生成两个等差数列
xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
YY, XX = np.meshgrid(yy, xx)
xy = np.vstack([XX.ravel(), YY.ravel()]).T
Z = clf.decision_function(xy).reshape(XX.shape)
# 把分类的决定边界画出来
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--'])
ax.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=100, linewidth=1, facecolors='none')
plt.savefig('./svm.png')
plt.show()
最后输出的图为:
图2 线性可分SVM图
3、面试算法题之剑指offer1:找出数组中重复的数字
3.1 题目描述
给定一个长度为 n 的整数数组 nums,数组中所有的数字都在 0∼n−1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
注意:如果某些数字不在 0∼n−1 的范围内,或数组中不包含重复数字,则返回 -1;
样例:给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。返回 2 或 3。
解题思路:遍历数组,然后将每个数字放在改放的位置,如nums[0]=0,nums[1]=1,....。
时间复杂度:O(N)
from collections import defaultdict
class Solution(object):
def duplicateInArray(self, nums):
"""
:type nums: List[int]
:rtype int
"""
counters = defaultdict(lambda:0)
range_right = len(nums)
res = -1 # save duplicate num
for num in nums:
if num not in range(range_right):
return -1 # none legal num in range 0 ~ n-1
if counters[num] > 0:
res = num
else:
counters[num] += 1
return res
4、参考文献
(1)《统计学习方法》
(2)《机器学习》
(3) Python-SVM (4)《剑指offer》