赞
踩
此文介绍了 S M O SMO SMO算法,以及前面我们介绍了支持向量机的理论,下面我们就该通过代码来实现了。
由于 S M O SMO SMO算法不易于理解,为了让大家正确理解它的工作流程,我们先从简化版的 S M O SMO SMO算法开始讨论。
【数据集以及代码】链接:https://pan.baidu.com/s/1mGQNPA4xmgUEANo1o8rHxg 密码:oq2g
通过之前的学习,我们知道 S M O SMO SMO算法中的外循环确定要优化的 α \alpha α,而简化版的会跳过这一部分,首先在训练数据集上遍历每一个 α \alpha α,然后在剩下的 α \alpha α集合中随机选取另一个 α \alpha α,从而构建 α \alpha α对。
这里有一点非常重要,之前我们也提到过,这里再说明一下:
我们需要同时改变两个变量 α \alpha α,因为约束条件:
α 1 y 1 + α 2 y 2 = − ∑ i = 3 N α i y i = ς \alpha_1y_1+\alpha_2y_2 = -\sum_{i=3}^N\alpha_iy_i=\varsigma α1y1+α2y2=−i=3∑Nαiyi=ς
其中, ς \varsigma ς为常数
为此,我们先构建一个辅助函数,用于在某个区间范围内随机选择一个整数;同时我们也需要另一个辅助函数,用于在数值太大时,对其进行调整;还有一个函数是加载数据集的。
代码如下:
import random from numpy import * # 加载数据集 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对应的数目 j = i while (j == i): j = int(random.uniform(0, m)) return j # 用于调整大于H或小于L的alpha值 def clipAlpha(aj, H, L): if aj > H: aj = H if L > aj: aj = L return aj # 测试 dataArr, labelArr = loadDataSet('testSet.txt') print(labelArr)
运行结果1:
[-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0,...
可以看出,这里采用的类别标签是-1和+1
简化版 S M O SMO SMO算法
伪代码如下:
创建一个alpha向量并将其初始化为0向量
当迭代次数小于最大迭代次数时(外循环):
对数据集中的每个数据向量(内循环):
如果该数据向量可以被优化:
随机选择另一个数据向量
同时优化这两个向量
如果两个向量都不能被优化,退出内循环
如果所有向量都没有被优化,增加迭代次数,继续下一次循环
python3 代码:
# 简化版SMO算法 def smoSimple(dataMatIn, classLabels, C, toler, maxIter): # 数据集、类别标签、常数C、容错率和退出前最大的循环次数 dataMatrix = mat(dataMatIn) # 将数据集用mat函数转换为矩阵 labelMat = mat(classLabels).transpose() # 转置类别标签(使得类别标签向量的每行元素都和数据矩阵中的每一行一一对应) b = 0 m, n = shape(dataMatrix) # 通过矩阵的shape属性得到常数m,n alphas = mat(zeros((m, 1))) # 构建一个alpha列矩阵,初始化为0 iter = 0 # 建立一个iter变量(该变量存储在没有任何alpha改变的情况下遍历数据集的次数,当该变量达到输入值maxIter时,函数结束) while (iter < maxIter): # 遍历数据集的次数小于输入的maxIter alphaPairsChanged = 0 # 用于记录alpha是否已经进行优化,先设为0 for i in range(m): # 顺序遍历整个集合 fXi = float(multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[i, :].T)) + b # fXi可以计算出来,是我们预测的类别 Ei = fXi - float(labelMat[i]) # 计算误差,基于这个实例的预测结果和真实结果的比对 if ((labelMat[i] * Ei < -toler) and (alphas[i] < C)) or ( (labelMat[i] * Ei > toler) and (alphas[i] > 0)): # 如果误差过大,那么对该数据实例对应的alpha值进行优化 j = selectJrand(i, m) # 随机选取第二个alpha,调用辅助函数selectJrand fXj = float(multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[j, :].T)) + b Ej = fXj - float(labelMat[j]) # 计算误差(同第一个alpha值的误差计算方法) alphaIold = alphas[i].copy() # 浅复制,两对象互不影响,为了稍后对新旧alpha值进行比较 alphaJold = alphas[j].copy() if (labelMat[i] != labelMat[j]): # 保证alpha值在0与C之间 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 # 本次循环结束,进入下一次for循环 eta = 2.0 * dataMatrix[i, :] * dataMatrix[j, :].T - \ dataMatrix[i, :] * dataMatrix[i, :].T - dataMatrix[j, :] * dataMatrix[j, :].T # alpha值的最优修改值 if eta >= 0: print("eta >= 0") continue alphas[j] -= labelMat[j] * (Ei - Ej) / eta # 计算出新的alpha[j]值 alphas[j] = clipAlpha(alphas[j], H, L) # 调用clipAlpha辅助函数以及L,H值对其进行调整 if (abs(alphas[j] - alphaJold) < 0.00001): # 检查alpha[j]是否有轻微改变,如果是的话,就退出for循环 print("J not moving enough!") continue alphas[i] += labelMat[j] * labelMat[i] * (alphaJold - alphas[j]) # 对alpha[i]进行同样的改变,改变大小一样方向相反 # 给alpha[i]和alpha[j]设置一个常数项b,等同于上篇博客中计算阀值b部分,可以对照看 b1 = b - Ei - labelMat[i] * (alphas[i] - alphaIold) * dataMatrix[i, :] * dataMatrix[i, :].T - \ labelMat[j] * (alphas[j] - alphaJold) * dataMatrix[i, :] * dataMatrix[j, :].T b2 = b - Ej - labelMat[i] * (alphas[i] - alphaIold) * dataMatrix[i, :] * dataMatrix[j, :].T - \ labelMat[j] * (alphas[j] - alphaJold) * dataMatrix[j, :] * dataMatrix[j, :].T if (0 < alphas[i]) and (C > alphas[i]): b = b1 elif (0 < alphas[j]) and (C > alphas[j]): b = b2 else: b = (b1 + b2) / 2.0 alphaPairsChanged += 1 # 当for循环运行到这一行,说明已经成功的改变了一对alpha值,同时让alphaPairsChanged加1 print("iter:%d i:%d,pairs changed %d" % (iter, i, alphaPairsChanged)) # for循环结束后,检查alpha值是否做了更新 if (alphaPairsChanged == 0): # 如果没有,iter加1 iter += 1 # 下面后回到while判断 else: # 如果有更新则iter设为0后继续运行程序 iter = 0 print("iteration number: %d" % iter) return b, alphas # (只有在所有数据集上遍历maxIter次,且不再发生任何alpha值修改之后,程序才会停止,并退出while循环) # 测试 b, alphas = smoSimple(dataArr, labelArr, 0.6, 0.001, 40) print(b) print(alphas[alphas > 0]) # 观察元素大于0的 shape(alphas[alphas > 0]) # 得到支持向量的个数 for i in range(100): if alphas[i] > 0.0: print("简单版支持向量为:", dataArr[i], labelArr[i])
运行结果2:
为了画出图形来,我们还需要计算w的值,如下:
python3 代码:
# 计算w的值
# 该程序最重要的是for循环,for循环中实现的仅仅是多个数的乘积,前面我们计算出的alpha值,大部分是为0
# 虽然遍历数据集中的所有数据,但是起作用的只有支持向量,其他对计算w毫无作用
def calcWs(alphas, dataArr, classLabels):
X = mat(dataArr)
labelMat = mat(classLabels).transpose()
m, n = shape(X)
w = zeros((n, 1))
for i in range(m):
w += multiply(alphas[i] * labelMat[i], X[i, :].T)
return w
ws = calcWs(alphas, dataArr, labelArr)
print(ws)
运行结果3:
画图代码:
将上面程序运行的结果输入下面代码:
from numpy import * import matplotlib import matplotlib.pyplot as plt from matplotlib.patches import Circle xcord0 = [] ycord0 = [] xcord1 = [] ycord1 = [] markers = [] colors = [] fr = open('testSet.txt') for line in fr.readlines(): lineSplit = line.strip().split('\t') xPt = float(lineSplit[0]) yPt = float(lineSplit[1]) label = int(lineSplit[2]) if (label == -1): xcord0.append(xPt) ycord0.append(yPt) else: xcord1.append(xPt) ycord1.append(yPt) fr.close() fig = plt.figure() ax = fig.add_subplot(111) ax.scatter(xcord0, ycord0, marker='s', s=90) ax.scatter(xcord1, ycord1, marker='o', s=50, c='red') plt.title('Support Vectors Circled') circle = Circle((4.658191, 3.507396), 0.5, facecolor='none', edgecolor=(0, 0.8, 0.8), linewidth=3, alpha=0.5) ax.add_patch(circle) circle = Circle((3.457096, -0.082216), 0.5, facecolor='none', edgecolor=(0, 0.8, 0.8),linewidth=3, alpha=0.5) ax.add_patch(circle) circle = Circle((5.286862, -2.358286), 0.5, facecolor='none', edgecolor=(0, 0.8, 0.8), linewidth=3,alpha=0.5) ax.add_patch(circle) circle = Circle((6.080573, 0.418886), 0.5, facecolor='none', edgecolor=(0, 0.8, 0.8), linewidth=3,alpha=0.5) ax.add_patch(circle) # plt.plot([2.3,8.5], [-6,6]) #seperating hyperplane b = -3.82407793 w0 = 0.81085367 w1 = -0.25395222 x = arange(-2.0, 12.0, 0.1) y = (-w0 * x - b) / w1 ax.plot(x, y) ax.axis([-2, 12, -8, 6]) plt.show()
运行结果4:
在几百个点 组成的小规模数据集上,简化版 S M O SMO SMO算法的运行是没有什么问题的,但是在更大的数据集上运行的速度就会很慢。
下面我们讨论完整版的 S M O SMO SMO算法。
在这两个版本中,实现 α \alpha α的更改和代数运算的优化环节一模一样。在优化过程中,唯一不同的就是选择 α \alpha α的方式。完整版 S M O SMO SMO算法应用了一些能够提速的启发式方法。
S M O SMO SMO算法是通过一个外循环来选择第一个 α \alpha α值的,并且其选择过程会在两种方式之间进行交替:
所谓非边界 α \alpha α,即:指那些不等于边界0或C的 α \alpha α值。
对整个数据集的扫描相当容易,而实现非边界扫描,首先需要建立这些 α \alpha α值的列表,然后再对这个列表进行遍历,同时该步骤会跳过那些已知的不会改变的 α \alpha α值。
在选择第一个 α \alpha α值后,算法会通过一个内循环来选择第二个 α \alpha α值。在优化过程中通过最大化步长来获取第二个 α \alpha α值。
我们建立一个全局的缓存用于保存误差值,从中选择使得步长或者 E i − E j E_i - E_j Ei−Ej最大的 α \alpha α值。
以下为用于清理代码的数据结构和3个用于对 E E E进行缓存的辅助函数:
完整版 S M O SMO SMO的支持函数
python3 代码:
# 完整版Platt SMO的支持函数 # (不加核函数)构建一个仅包含init方法的optStruct类,实现其成员变量的填充 class optStruct: def __init__(self, dataMatIn, classLabels, C, toler): self.X = dataMatIn self.labelMat = classLabels self.C = C self.tol = toler self.m = shape(dataMatIn)[0] self.alphas = mat(zeros((self.m, 1))) self.b = 0 self.eCache = mat(zeros((self.m, 2))) # 计算E值并返回 # 不加核函数 def calcEk(oS, k): fXk = float(multiply(oS.alphas, oS.labelMat).T * (oS.X * oS.X[k, :].T)) + oS.b Ek = fXk - float(oS.labelMat[k]) return Ek # 内循环中的启发式方法,选择第二个alpha def selectJ(i, oS, Ei): maxK = -1 maxDeltaE = 0 Ej = 0 oS.eCache[i] = [1, Ei] validEcacheList = nonzero(oS.eCache[:, 0].A)[0] # 构建出一个非零表,函数nonzero返回一个列表 # 在所有值上进行循环并选择其中使得该变量最大的那个值 if (len(validEcacheList)) > 1: for k in validEcacheList: if k == i: continue Ek = calcEk(oS, k) deltaE = abs(Ei - Ek) if (deltaE > maxDeltaE): maxK = k maxDeltaE = deltaE Ej = Ek return maxK, Ej else: j = selectJrand(i, oS.m) Ej = calcEk(oS, j) return j, Ej # 计算误差值并存入缓存中,在对alpha值进行优化之后会用到这个值 def updateEk(oS, k): Ek = calcEk(oS, k) oS.eCache[k] = [1, Ek]
完整版$SMO#算法内外循环函数
# 完整Platt SMO算法中的优化例程(与smoSimple()函数一样,只是使用了自己的数据结构,在参数oS中传递) # innerL()函数用来选择第二个alpha,并在可能是对其进行优化处理,如果存在任意一对alpha值发生变化,那么返回1 # 不加核函数 def innerL(i, oS): Ei = calcEk(oS, i) # 计算E值 if ((oS.labelMat[i] * Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or \ ((oS.labelMat[i] * Ei > oS.tol) and (oS.alphas[i] > 0)): j, Ej = selectJ(i, oS, Ei) # 第二个alpha选择中的启发式方法 alphaIold = oS.alphas[i].copy() alphaJold = oS.alphas[j].copy() if (oS.labelMat[i] != oS.labelMat[j]): L = max(0, oS.alphas[j] - oS.alphas[i]) H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i]) else: L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C) H = min(oS.C, oS.alphas[j] + oS.alphas[i]) if L == H: print("L==H") return 0 eta = 2.0 * oS.X[i, :] * oS.X[j, :].T - oS.X[i, :] * oS.X[i, :].T - oS.X[j, :] * oS.X[j, :].T if eta >= 0: print("eta>=0") return 0 oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej) / eta oS.alphas[j] = clipAlpha(oS.alphas[j], H, L) updateEk(oS, j) # 计算误差值,并存入缓存 if (abs(oS.alphas[j] - alphaJold) < 0.00001): print("j not moving enough") return 0 oS.alphas[i] += oS.labelMat[j] * oS.labelMat[i] * (alphaJold - oS.alphas[j]) updateEk(oS, i) b1 = oS.b - Ei - oS.labelMat[i] * (oS.alphas[i] - alphaIold) * oS.X[i, :] * oS.X[i, :].T - oS.labelMat[j] * \ (oS.alphas[j] - alphaJold) * oS.X[i, :] * oS.X[j, :].T b2 = oS.b - Ej - oS.labelMat[i] * (oS.alphas[i] - alphaIold) * oS.X[j, :] * oS.X[j, :].T - oS.labelMat[j] * \ (oS.alphas[j] - alphaJold) * oS.X[j, :] * oS.X[j, :].T if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1 elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2 else: oS.b = (b1 + b2) / 2.0 return 1 else: return 0 # 完整版Platt SMO的外循环代码 # 不加核函数 def smoP(dataMatIn, classLabels, C, toler, maxIter): # 数据集、类别标签、常数C、容错率和退出前最大的循环次数 oS = optStruct(mat(dataMatIn), mat(classLabels).transpose(), C, toler) # 构建一个数据结构来容纳所有的数据 # 初始化一些控制变量 iter = 0 entireSet = True alphaPairsChanged = 0 # 代码主体 # 退出循环的条件: # 1、迭代次数超过指定的最大值; # 2、历整个集合都没有对任意alpha值进行修改(即:alphaPairsChanged=0) while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): alphaPairsChanged = 0 if entireSet: # 遍历所有的值 for i in range(oS.m): alphaPairsChanged += innerL(i, oS) # 调用innerL()函数 print("fullSet, iter: %d i:%d, pairs changed %d" % (iter, i, alphaPairsChanged)) iter += 1 else: # 遍历非边界值(非边界值指的是那些不等于边界0或C的alpha值) nonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] for i in nonBoundIs: alphaPairsChanged += innerL(i, oS) print("non-bound, iter: %d i:%d, pairs changed %d" % (iter, i, alphaPairsChanged)) iter += 1 if entireSet: entireSet = False elif (alphaPairsChanged == 0): entireSet = True print("iteration number: %d" % iter) return oS.b, oS.alphas
测试代码:
# 测试 dataArr, labelArr = loadDataSet('testSet.txt') b, alphas = smoP(dataArr, labelArr, 0.6, 0.001, 40) print(b) print(alphas[alphas > 0]) # 观察元素大于0的 shape(alphas[alphas > 0]) # 得到支持向量的个数 for i in range(100): if alphas[i] > 0.0: print("完整版支持向量为:", dataArr[i], labelArr[i]) # 计算w的值 # 该程序最重要的是for循环,for循环中实现的仅仅是多个数的乘积,前面我们计算出的alpha值,大部分是为0 # 虽然遍历数据集中的所有数据,但是起作用的只有支持向量,其他对计算w毫无作用 def calcWs(alphas, dataArr, classLabels): X = mat(dataArr) labelMat = mat(classLabels).transpose() m, n = shape(X) w = zeros((n, 1)) for i in range(m): w += multiply(alphas[i] * labelMat[i], X[i, :].T) return w ws = calcWs(alphas, dataArr, labelArr) print(ws) # 对数据进行分类处理 dataMat = mat(dataArr) print(dataMat[0] * mat(ws) + b) print(labelArr[0]) dataMat = mat(dataArr) print(dataMat[1] * mat(ws) + b) print(labelArr[1]) dataMat = mat(dataArr) print(dataMat[2] * mat(ws) + b) print(labelArr[2])
运行结果5:
将程序运行结果代入画图代码同样可以画出图:
图中我们可以看出,这两个类的数据点分布在一条直线的两侧,我们可以得到两类的分割线。但倘若两类数据集分布在一个圆的内部和外部呢?
之前博客理论部分我们以及说明了非线性支持向量机,使用核技巧
下面我们就来讨论在复杂数据上应用核函数
代码如下:
import random from numpy import * 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 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 # 加核函数 def calcEkK(oS, k): fXk = float(multiply(oS.alphas, oS.labelMat).T * oS.K[:, k] + oS.b) Ek = fXk - float(oS.labelMat[k]) return Ek # 内循环中的启发式方法,选择第二个alpha def selectJK(i, oS, Ei): maxK = -1 maxDeltaE = 0 Ej = 0 oS.eCache[i] = [1, Ei] validEcacheList = nonzero(oS.eCache[:, 0].A)[0] # 构建出一个非零表,函数nonzero返回一个列表 # 在所有值上进行循环并选择其中使得该变量最大的那个值 if (len(validEcacheList)) > 1: for k in validEcacheList: if k == i: continue Ek = calcEkK(oS, k) deltaE = abs(Ei - Ek) if (deltaE > maxDeltaE): maxK = k maxDeltaE = deltaE Ej = Ek return maxK, Ej else: j = selectJrand(i, oS.m) Ej = calcEkK(oS, j) return j, Ej # 计算误差值并存入缓存中,在对alpha值进行优化之后会用到这个值 def updateEkK(oS, k): Ek = calcEkK(oS, k) oS.eCache[k] = [1, Ek] # 核转换函数 def kernelTrans(X, A, kTup): # 2个数值型变量和一个元祖,kTup是一个包含核函数信息的元祖,该元祖的第一个参数描述的是所用核函数的类型的一个字符串 m, n = shape(X) K = mat(zeros((m, 1))) if kTup[0] == 'lin': # 线性核函数,内积计算在“所有数据集”和“数据集中的一行”这两个输入之间展开 K = X * A.T elif kTup[0] == 'rbf': # 径向核函数,在for循环中对矩阵的每个元素计算高斯函数值 for j in range(m): deltaRow = X[j, :] - A K[j] = deltaRow * deltaRow.T K = exp(K / (-1 * kTup[1] ** 2)) else: raise NameError('Houston We have a Problem -- That Kernel is not recognized') # 遇到无法识别的核函数抛出异常 return K class optStruct: def __init__(self, dataMatIn, classLabels, C, toler, kTup): self.X = dataMatIn self.labelMat = classLabels self.C = C self.tol = toler self.m = shape(dataMatIn)[0] self.alphas = mat(zeros((self.m, 1))) self.b = 0 self.eCache = mat(zeros((self.m, 2))) self.K = mat(zeros((self.m, self.m))) for i in range(self.m): self.K[:, i] = kernelTrans(self.X, self.X[i, :], kTup) # 加入核函数 def innerLK(i, oS): Ei = calcEkK(oS, i) # 计算E值 if ((oS.labelMat[i] * Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or \ ((oS.labelMat[i] * Ei > oS.tol) and (oS.alphas[i] > 0)): j, Ej = selectJK(i, oS, Ei) # 第二个alpha选择中的启发式方法 alphaIold = oS.alphas[i].copy() alphaJold = oS.alphas[j].copy() if (oS.labelMat[i] != oS.labelMat[j]): L = max(0, oS.alphas[j] - oS.alphas[i]) H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i]) else: L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C) H = min(oS.C, oS.alphas[j] + oS.alphas[i]) if L == H: print("L==H") return 0 eta = 2.0 * oS.K[i, j] - oS.K[i, i] - oS.K[j, j] if eta >= 0: print("eta>=0") return 0 oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej) / eta oS.alphas[j] = clipAlpha(oS.alphas[j], H, L) updateEkK(oS, j) # 计算误差值,并存入缓存 if (abs(oS.alphas[j] - alphaJold) < 0.00001): print("j not moving enough") return 0 oS.alphas[i] += oS.labelMat[j] * oS.labelMat[i] * (alphaJold - oS.alphas[j]) updateEkK(oS, i) b1 = oS.b - Ei - oS.labelMat[i] * (oS.alphas[i] - alphaIold) * oS.K[i, i] - oS.labelMat[j] * \ (oS.alphas[j] - alphaJold) * oS.K[i, j] b2 = oS.b - Ej - oS.labelMat[i] * (oS.alphas[i] - alphaIold) * oS.K[i, j] - oS.labelMat[j] * \ (oS.alphas[j] - alphaJold) * oS.K[j, j] if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1 elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2 else: oS.b = (b1 + b2) / 2.0 return 1 else: return 0 # 加入核函数 def smoPK(dataMatIn, classLabels, C, toler, maxIter, kTup=('lin', 0)): oS = optStruct(mat(dataMatIn), mat(classLabels).transpose(), C, toler, kTup) iter = 0 entireSet = True alphaPairsChanged = 0 while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): alphaPairsChanged = 0 if entireSet: for i in range(oS.m): alphaPairsChanged += innerLK(i, oS) print("fullSet, iter: %d i:%d, pairs changed %d" % (iter, i, alphaPairsChanged)) iter += 1 else: nonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] for i in nonBoundIs: alphaPairsChanged += innerLK(i, oS) print("non-bound, iter: %d i:%d, pairs changed %d" % (iter, i, alphaPairsChanged)) iter += 1 if entireSet: entireSet = False # toggle entire set loop elif (alphaPairsChanged == 0): entireSet = True print("iteration number: %d" % iter) return oS.b, oS.alphas # 利用核函数进行分类的径向基测试函数 def testRbf(k1=1.3): # 参数为高斯径向基函数中的一个用户定义变量 dataArr, labelArr = loadDataSet('testSetRBF.txt') # 读入数据集 b, alphas = smoPK(dataArr, labelArr, 200, 0.0001, 10000, ('rbf', k1)) # 调用函数smoP,核函数类型为"rbf" datMat = mat(dataArr) labelMat = mat(labelArr).transpose() svInd = nonzero(alphas.A > 0)[0] sVs = datMat[svInd] # 构建支持向量矩阵 labelSV = labelMat[svInd] print("there are %d Support Vectors" % shape(sVs)[0]) m, n = shape(datMat) errorCount = 0 for i in range(m): # 整个代码最重要部分(for循环开始的这两行),给出如何利用核函数进行分类 kernelEval = kernelTrans(sVs, datMat[i, :], ('rbf', k1)) # 调用kernelTrans()核转换函数 predict = kernelEval.T * multiply(labelSV, alphas[svInd]) + b # 与其面的alpha及类别标签值求积 if sign(predict) != sign(labelArr[i]): errorCount += 1 print("the training error rate is: %f" % (float(errorCount) / m)) dataArr, labelArr = loadDataSet('testSetRBF2.txt') errorCount = 0 datMat = mat(dataArr) labelMat = mat(labelArr).transpose() m, n = shape(datMat) for i in range(m): # 与前面一个for循环相比,只是数据集不同,使用的是测试数据集 kernelEval = kernelTrans(sVs, datMat[i, :], ('rbf', k1)) predict = kernelEval.T * multiply(labelSV, alphas[svInd]) + b if sign(predict) != sign(labelArr[i]): errorCount += 1 print("the test error rate is: %f" % (float(errorCount) / m)) # 测试 testRbf()
运行结果6:
你可以尝试更换不同的 k 1 k1 k1值以观察测试错位率、训练错误率,支持向量个数
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。