机器学习实战之支持向量机(Support Vector Machine)
理论知识
支持向量机分为:
- 线性可分支持向量机
- 线性支持向量机
- 非线性支持向量机
支持向量机的本质为求解一个凸二次规划问题,如今使用最广泛的求法为SMO(Sequential Minimal optimization)算法
在这里,不过多介绍理论知识,主要介绍实战内容
SVM应用的一般框架
- 收集数据
- 准备数据:数值型数据
- 分析数据
- 训练算法:SVM的大部分时间源自训练,该过程主要实现两个参数的调优
- 测试算法
- 使用算法:适用于几乎所有分类问题。
值得注意的是,SVM本身为一个二分类算法,如果要进行多分类,需要对SVM算法做一定修改。
SMO高效优化算法
SVM本质上是在求解一个凸二次规划问题,可以用常规的求解二次规划问题的算法来求解,但Platt提出的SMO是一个更高效的求解算法。
Platt的SMO算法
SMO算法是将大优化问题分解为多个小优化问题来求解。这些小优化问题往往易于求解,并且对它们进行顺序求解的结果与将它们作为整体来求解的结果是完全一致的。(类似于分治算法)
其工作原理为:
每次循环中选择两个alpha进行优化处理。
一旦找到一对合适的alpha,就增大其中一个同时减少另一个。
应用简化版SMO算法处理小规模数据集
简化版SMO选择两个alpha的规则为:
首先在数据集上遍历每一个alpha,然后在剩下的alpha集合总随机选择另一个alpha,从而构成alpha对。
其伪代码为:
创建一个alpha向量并将其初始化为0向量
当迭代次数小于最大迭代次数时(外循环)
对数据集中的每个数据向量(内循环):
如果该数据向量可以被优化:
随机选择另一个数据向量
同时优化这两个向量
如果两个向量都不能被优化,退出内循环
如果所有向量都没被优化,增加迭代次数,继续下一次循环。
一些辅助函数:
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):
"""
i为第一个alpha的下标
m为所有alpha的数目
即随机选择第二个alpha
"""
j = i
while (j == i):
j = int(random.uniform(0, m))
return j
def clipAlpha(aj, H, L):
"""
用于调整大于H活小于L的alpha值
"""
if aj > H:
aj = H
if L > aj:
aj = L
return aj
简化版SMO算法代码如下:
from numpy import *
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
"""
dataMatIn: 数据集
classLabels: 类别标签
C
toler: 容错率
maxIter: 退出前的最大迭代次数
"""
dataMatrix = mat(dataMatIn)
labelMat = mat(classLabels).transpose() # 类别标签转换为列向量
b = 0
m, n = shape(dataMatrix)
alphas = mat(zeros((m, 1))) # alpha向量,存储所有alpha
iter = 0 # 存储没有任何alpha改变的情况下遍历数据集的次数
while (iter < maxIter):
alphaPairsChanged = 0 # 记录alpha是否已经进行优化
for i in range(m):
fXi = float(multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[i, :].T)) + b # 预测的类别
Ei = fXi - float(labelMat[i]) # 预测结果与真实结果的误差Ei
# 如果误差较大,对alpha进行优化
if ((labelMat[i] * Ei < -toler) and (alphas[i] < C) or ((labelMat[i] * Ei > toler) and (alphas[i] > 0))):
j = selectJrand(i, m) # 随机选择第二个alpha值
fXj = float(multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[j, :].T)) + b #
Ej = fXj - float(labelMat[j]) #
alphaIold = alphas[i].copy()
alphaJold = alphas[i].copy()
if (labelMat[i] != labelMat[j]):
L = max(0, alphas[j] - alphas[i])
H = min(C, C + alphas[j] - alphas[i])
else:
L = max(0, alphas[j] + alphas[i] - C)
H = min(C, alphas[j] + alphas[i])
if L == H:
print("L == H")
continue
# eta为alphas[j]的最佳修改量
eta = 2.0 * dataMatrix[i, :] * dataMatrix[j, :].T - dataMatrix[i, :] * dataMatrix[i, :].T - dataMatrix[j, :] * dataMatrix[j, :].T
if eta >= 0:
print("eat >= 0")
continue
alphas[j] -= labelMat[j] * (Ei - Ej) / eta
alphas[j] = clipAlpha(alphas[j], H,