一、基于最大间隔分隔数据
支持向量机
优点:泛化错误率低,计算开销不大,结果易解释
缺点:对参数调节和核函数的选择敏感,原始分类器不加修改仅适用于处理二类问题。
适用数据类型:数值型和标称型数据。
线性可分:如图6-2方框A中的两组数据,它们之间分的足够开,可以很容易就在数据中给出一条直线将两组数据点分开。
分隔超平面:将上述将数据集分隔开来的直线。
在上面给出的例子中,由于数据点都在二维平面上,所以此时分隔超平面就只是一条直线。但是,如果所给的数据集是三维的,那么此时用来分隔数据的就是一个平面。显而易见,如果数据集是N维的,那么就需要一个N-1维的对象来对数据进行分隔。 该对象被称为超平面,也就是分类的决策边界。分布在超平面一侧的所有数据都属于某个类别,而分布在另一侧的所有数据则属于另一个类别。
支持向量:离分隔超平面最近的那些点。
二、寻找最大间隔
以图6-3为例,分隔超平面的形式可以写成,点A到分隔超平面的法线长度
最大化间隔的目标就是找出分类器定义中的w和b。为此,我们必须找到具有最小间隔的数据点,而这些数据点也就是前面提到的支持向量。一旦找到具有最小间隔的数据点,我们就需要对该间隔最大化。这就可以写作:
直接求解上述问题相当困难,所以我们将它转换成为另一种更容易求解的形式。通过引人拉格朗日乘子,我们就可以基于约束条件来表述原来的问题。由于这里的约束条件都是基于数据点的,因此我们就可以将超平面写成数据点的形式。于是,优化目标函数最后可以写成:
其约束条件为:
三、SMO高效优化算法
简化版SMO算法,省略了确定要优化的最佳alpha对的步骤,而是首先在数据集上遍历每一个alpha, 然后在剩下的alpha集合中随机选择另一个alpha, 从而构建alpha对。这里有一点相当重要,就是我们要同时改变两个alphao之所以这样做是因为我们有一个约束条件:
由于改变一个alpha可能会导致该约束条件失效,因此我们总是同时改变两个alpha。
SMO算法中的辅助函数
def loadDataSet(fileName):
dataMat = []; labelMat = []
fr = open(fileName)
for line in fr.readlines():
lineArr = line.strip().split('\t')
dataMat.append([float(lineArr[0]), float(lineArr[1])])
labelMat.append(float(lineArr[2]))
return dataMat,labelMat
def selectJrand(i,m):
j=i #we want to select any J not equal to i
while (j==i):
j = int(random.uniform(0,m))
return j
def clipAlpha(aj,H,L):
if aj > H:
aj = H
if L > aj:
aj = L
return aj
第一个函数是loadDatSet()函数,该函数打开文件并对其进行逐行解析,从而得到每行的类标签和整个数据矩阵。
下一个函数selectJrand()有两个参数值,其中i是第一个alpha的下标,m是所有alpha的数目。只要函数值不等于输人值i,函数就会进行随机选择。
最后一个辅助函数就是clipA1pha(),它是用于调整大于H或小于L的alpha值。
尽管上述3个辅助函数本身做的事情不多,但在分类器中却很有用处。
简化版SMO算法
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
dataMatrix = mat(dataMatIn); labelMat = mat(classLabels).transpose()
b = 0; m,n = shape(dataMatrix)
alphas = mat(zeros((m,1)))
iter = 0
while (iter < maxIter):
alphaPairsChanged = 0
for i in range(m):
fXi = float(multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b
Ei = fXi - float(labelMat[i])#if checks if an example violates KKT conditions
if ((labelMat[i]*Ei < -toler) and (alphas[i]