

SMO算法的工作原理是:每次循环中选择两个alpha进行优化处理。一旦找到了一对合适的alpha,那么就增大其中一个同时减小另一个。这里所谓的”合适”就是指两个alpha必须符合以下两个条件,条件之一就是两个alpha必须要在间隔边界之外,而且第二个条件则是这两个alpha还没有进进行过区间化处理或者不在边界上。
import matplotlib.pyplot as pltimport numpy as npdef 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,labelMatdef showDataSet(dataMat, labelMat):data_plus = [] #正样本data_minus = [] #负样本for i in range(len(dataMat)):if labelMat[i] > 0:data_plus.append(dataMat[i])else:data_minus.append(dataMat[i])data_plus_np = np.array(data_plus) #转换为numpy矩阵data_minus_np = np.array(data_minus) #转换为numpy矩阵plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1]) #正样本散点图plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1]) #负样本散点图plt.show()if __name__ == '__main__':dataMat, labelMat = loadDataSet('testSet.txt')showDataSet(dataMat, labelMat)

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,labelMatdef selectJrand(i, m):j = i #选择一个不等于i的jwhile (j == i):j = int(random.uniform(0, m))return jdef clipAlpha(aj,H,L):if aj > H:aj = Hif L > aj:aj = Lreturn ajdef smoSimple(dataMatIn, classLabels, C, toler, maxIter):#转换为numpy的mat存储dataMatrix = np.mat(dataMatIn); labelMat = np.mat(classLabels).transpose()#初始化b参数,统计dataMatrix的维度b = 0; m,n = np.shape(dataMatrix)#初始化alpha参数,设为0alphas = np.mat(np.zeros((m,1)))#初始化迭代次数iter_num = 0#最多迭代matIter次while (iter_num < maxIter):alphaPairsChanged = 0for i in range(m):#步骤1:计算误差EifXi = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + bEi = fXi - float(labelMat[i])#优化alpha,更设定一定的容错率。if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):#随机选择另一个与alpha_i成对优化的alpha_jj = selectJrand(i,m)#步骤1:计算误差EjfXj = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + bEj = fXj - float(labelMat[j])#保存更新前的aplpha值,使用深拷贝alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();#步骤2:计算上下界L和Hif (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#步骤3:计算etaeta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T - dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].Tif eta >= 0: print("eta>=0"); continue#步骤4:更新alpha_jalphas[j] -= labelMat[j]*(Ei - Ej)/eta#步骤5:修剪alpha_jalphas[j] = clipAlpha(alphas[j],H,L)if (abs(alphas[j] - alphaJold) < 0.00001): print("alpha_j变化太小"); continue#步骤6:更新alpha_ialphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])#步骤7:更新b_1和b_2b1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].Tb2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].T#步骤8:根据b_1和b_2更新bif (0 < alphas[i]) and (C > alphas[i]): b = b1elif (0 < alphas[j]) and (C > alphas[j]): b = b2else: b = (b1 + b2)/2.0#统计优化次数alphaPairsChanged += 1#打印统计信息print("第%d次迭代 样本:%d, alpha优化次数:%d" % (iter_num,i,alphaPairsChanged))#更新迭代次数if (alphaPairsChanged == 0): iter_num += 1else: iter_num = 0print("迭代次数: %d" % iter_num)return b,alphasdef showClassifer(dataMat, w, b):#绘制样本点data_plus = [] #正样本data_minus = [] #负样本for i in range(len(dataMat)):if labelMat[i] > 0:data_plus.append(dataMat[i])else:data_minus.append(dataMat[i])data_plus_np = np.array(data_plus) #转换为numpy矩阵data_minus_np = np.array(data_minus) #转换为numpy矩阵plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1], s=30, alpha=0.7) #正样本散点图plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1], s=30, alpha=0.7) #负样本散点图#绘制直线x1 = max(dataMat)[0]x2 = min(dataMat)[0]a1, a2 = wb = float(b)a1 = float(a1[0])a2 = float(a2[0])y1, y2 = (-b- a1*x1)/a2, (-b - a1*x2)/a2plt.plot([x1, x2], [y1, y2])#找出支持向量点for i, alpha in enumerate(alphas):if abs(alpha) > 0:x, y = dataMat[i]plt.scatter([x], [y], s=150, c='none', alpha=0.7, linewidth=1.5, edgecolor='red')plt.show()def get_w(dataMat, labelMat, alphas):alphas, dataMat, labelMat = np.array(alphas), np.array(dataMat), np.array(labelMat)w = np.dot((np.tile(labelMat.reshape(1, -1).T, (1, 2)) * dataMat).T, alphas)return w.tolist()if __name__ == '__main__':dataMat, labelMat = loadDataSet('testSet.txt')b,alphas = smoSimple(dataMat, labelMat, 0.6, 0.001, 40)w = get_w(dataMat, labelMat, alphas)showClassifer(dataMat, w, b)

