SMO算法

代码:

import random

import numpy as np

"""
函数说明:随机选择alpha
Parameters:
    i - alpha
    m - alpha参数个数
Returns:
    j -
"""


def selectJrand(i, m):
    j = i
    while (j == i):
        j = int(random.uniform(0, m))
    return j


""""
函数说明:根据上下限修剪alpha
Parameters:
    alpha_j - alpha值
    H - alpha上限
    L - alpha下限
Returns:
    alpha_j - alpha值
"""


def clipAlpha(alpha_j, H, L):
    if alpha_j > H:
        alpha_j = H
    if alpha_j < L:
        alpha_j = L
    return alpha_j


"""
函数说明:简化版SMO算法
Parameters:
    dataMatIn - 数据矩阵 x
    classLabels - 数据标签 y
    C - 松弛变量
    toler - 容错率
    maxIter - 最大迭代次数
Returns:
    无
"""

"""
未修剪前
alpha_2_new =alpha_2_old + y_2*(E1-E2)/eta
eta = K_11 + K_22 - 2K_12
alpha_1_new =(C - alpha2_new*y_2)*y_1
"""


def smoSimple(dataMatIn, classLables, C, toler, maxIter):
    dataMatrix = np.mat(dataMatIn)  # 将传入的数据矩阵转换为numpy的mat存储 x
    labelMat = np.mat(classLables).transpose()  # 将传入的数据标签y转置
    b = 0
    m, n = np.shape(dataMatrix)  # 获得数据维度 m行n列,也可以看做有m个数据样本,n个特征
    alphas = np.mat(np.zeros((m, 1)))
    iter_num = 0  # 初始化迭代次数
    # 最多迭代maxIter次
    while (iter_num < maxIter):
        alphaPairsChanged = 0  # 用于记录alphas是否已经进行优化
        for i in range(m):
            # 有m个数据样本,遍历m次
            #  步骤1:计算误差Ei
            # 决策公式f(x) = sign(wx+b) = f(x) = ∑alpha_i*y_i*<x_i,x> + b
            # dataMatrix[i,:]表示矩阵中第i行所有元素
            # np.multiply(a,b) 将a,b中对应元素相乘
            fXi = float(np.multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[i, :].T)) + b
            # 求Ei = fXi -y_i
            Ei = fXi - float(labelMat[i])
            # 优化alpha,更设定一定的容错率
            # 下面就是界定非边界的alpha,正负间隔都会被测试,筛选满足KKT条件的,在边界上的alpha等于0或者C,则不再优化
            if ((labelMat[i] * Ei < - toler) and (alphas[i] < C)) or ((labelMat[i] * Ei > toler) and (alphas[i] > 0)):
                # y_i *Ei <toler且alphas[i] <c 或者 y_i*Ei>toler 且alphas[i] >0
                # 随机选择另一个与alphas_i成对优化的alphas_j
                j = selectJrand(i, m)
                # 计算误差Ej
                fXj = float(np.multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[j, :].T)) + b
                Ej = fXj - float(labelMat[j])
                # 保存更新前的alphas值 在更新或比较时会用到
                # 即alpha1_old ,alpha2_old
                alphaIold = alphas[i].copy()
                alphaJold = alphas[j].copy()
                # 步骤2:计算上下界L,H 将数学分析得到的结果直接带入
                if labelMat[i] != labelMat[j]:
                    L = max(0, alphas[j] - alphas[i])
                    H = min(C, C - alphas[i] + alphas[j])
                else:
                    L = max(0, alphas[i] + alphas[j] - C)
                    H = min(C, alphas[i] + alphas[j])
                if L == H:
                    print('L==H')
                    continue  # 如果上下界相等,则跳出本次for循环

                # 步骤3 计算eta 参数更新里的:K_11 + K_22 - 2K_12,有点不同,是因为假设条件不一样,但是原理相同
                eta = dataMatrix[i, :] * dataMatrix[i, :].T + dataMatrix[j, :] * dataMatrix[j, :].T - 2.0 * dataMatrix[
                                                                                 i, :] * dataMatrix[j, :].T
                if eta <= 0:
                    print('eta <=0')
                    continue  # 满足KKT条件,跳出该循序
                # 步骤4: 否则更新alphas[j]
                alphas[j] = alphas[j] + labelMat[j] * (Ei - Ej) / eta
                # 步骤5:修剪alphas[j]
                alphas[j] = clipAlpha(alphas[j], H, L)
                # abs 函数  返回数字的绝对值
                # 查看更新后的alpha是否满足条件,即变化大不大,如果不大,说明该alpha已经趋于稳定了,不用继续更新了
                if (abs(alphas[j] - alphaJold) < 0.00001):
                    # print(f'对于样本{i},alpha_j变化太小')
                    continue  # 对于第i个样本 alpha_j 变化太小,舍弃这个alpha_i 跳出循环,重新选择第一个变量
                # 若变化满足要求,则更新alpha_i
                # alphas[i] = (C - alphas[j]*labelMat[j])*labelMat[i] =alphas[i] = alphas[i] +(alphaJold - alphas[j])*labelMat[i]*labelMat[j]
                # alpha[i] = alpha[i] + y_j *y_i*(alphaJold - alphas[j])
                alphas[i] = alphas[i] + (alphaJold - alphas[j]) * labelMat[i] * labelMat[j]
                # 更新b
                b1 = b - Ei + (alphaIold - alphas[i]) * labelMat[i] * dataMatrix[i, :] * dataMatrix[i, :].T + (
                        alphaJold - alphas[j]) * labelMat[j] * dataMatrix[j, :] * dataMatrix[i, :].T
                b2 = b - Ej + (alphaIold - alphas[i]) * labelMat[i] * dataMatrix[j, :] * dataMatrix[i, :].T + (
                        alphaJold - alphas[j]) * labelMat[j] * 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  # 当运行到这里说明alpha已经进行更新了,因此更新优化次数加一
                print("第%d次迭代 样本:%d, alpha优化次数:%d" % (iter_num, i, alphaPairsChanged))
        if (alphaPairsChanged == 0):
            # 若经过了for循环alpha更新次数依然为0
            # 意味着这一轮迭代已经无法再优化参数,故迭代次数加一进入下一轮迭代
            # 若alpha优化次数为0 则进行下一次迭代
            # 若迭代次数一直加到最大迭代次数,则表明次数参数已经接近最优,无法再被优化,则跳出循环
            iter_num += 1
        else:
            # 若alpha更新次数有增加,即alpha还能再优化,则将迭代次数设为0,
            # 将已经更新优化好的参数重新作为起始参数,进入下一轮迭代更新
            iter_num = 0
        print("迭代次数: %d" % iter_num)
        # print('已经跑完一遍')
    return b, alphas


def loadDataSet(filename):
    dataMat = []
    labelMat = []
    fr = open(filename)
    for line in fr.readlines():  # 逐行读取,略除空格
        # print(line)
        lineArr = line.strip().split('\t')
        dataMat.append([float(lineArr[0]), float(lineArr[1])])  # 添加数据
        labelMat.append(float(lineArr[2]))
    return dataMat, labelMat


if __name__ == '__main__':
    dataMat, labelMat = loadDataSet('datasets/testSets.txt')
    b, alphas = smoSimple(dataMat, labelMat, 0.6, 0.001, 40)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值