机器学习第五节,支持向量机(SVM)

SVM:二类分类器,对多类问题应用SVM应该做一些修改

 

分隔超平面(separating hyperplane): 分类的决策边界

间隔(margin): 点到分隔面的距离。我们希望间隔尽可能大

支持向量(support vector): 离分隔超平面最近的那些点。

 

目标:最大化支持向量到分隔面的距离

分隔超平面:wTx+b

点到分隔面法线的长度:|wTx+b|/||w||

 

为什么标签用-1+1?不是01

因为可以用一个统一的公式来表示间隔:label*(wTx+b)

无论数据点处于正负方向,如果点离分隔平面很远的位置时,距离总是一个很大的正数。

 

目标:寻找w,b

找到最小间隔的数据点,对该间隔最大化:

argmaxw,b {minn(label*(wTx+b))*1/||w||}


这里推导根据andrew ng的课程来看:





应用简化版SMO算法处理小规模数据集:

import numpy as np


def load_dataset(filename):
    dataset = []
    labels = []
    fr = open(filename)
    for line in fr.readlines():
        split_line = line.strip().split('\t')
        dataset.append([float(split_line[0]), float(split_line[1])])
        labels.append(float(split_line[2]))

    return dataset, labels


def select_j_rand(i, m):
    '''
        随机选择另一个alphaj,与i构成alpha对
    '''
    j = i
    while j == i:
        j = int(np.random.uniform(0, m))

    return j


def clip_alpha(aj, H, L):
    '''
        约束alpha范围在0-C
    '''
    if aj > H:
        aj = H
    if aj < L:
        aj = L

    return aj


def smo_simple(dataset, labels, C, toler, max_iter):
    '''
        简化的smo算法(svm实现)
    :param dataset: 数据集
    :param labels: 标签集
    :param C: 松弛变量
    :param toler: 容错率
    :param max_iter: 最大循环次数
    :return:
    '''
    data_matrix = np.mat(dataset)
    labels_matrix = np.mat(labels).transpose()
    b = 0
    m, n = np.shape(data_matrix)
    alphas = np.mat(np.zeros((m, 1)))
    it = 0
    while it < max_iter:
        alpha_pari_changed = 0
        for i in range(m):
            # 预测值 h(x) = w'x+b = ∑ αi*yi*<xi,x>+b
            fxi = float(np.multiply(alphas, labels_matrix).T * (data_matrix*data_matrix[i, :].T)) + b
            # 误差
            ei = fxi - float(labels_matrix[i])
            # 如果alpha可以更改进入优化过程
            if ((labels_matrix[i]*ei < -toler) and (alphas[i] < C)) or \
                    ((labels_matrix[i]*ei > toler) and (alphas[i] > 0)):
                j = select_j_rand(i, m)
                fxj = float(np.multiply(alphas, labels_matrix).T * (data_matrix*data_matrix[j, :].T)) + b
                ej = fxj - float(labels_matrix[j])
                alpha_i_old = alphas[i].copy()
                alpha_j_old = alphas[j].copy()
                # 保证alpha在0与C之间
                if labels_matrix[i] != labels_matrix[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
                # alpha[j]的最优修改量
                eta = 2.0 * data_matrix[i, :]*data_matrix[j, :].T - \
                      data_matrix[i, :]*data_matrix[i, :].T - \
                      data_matrix[j, :]*data_matrix[j, :].T
                if eta >= 0:
                    print('eta>=0')
                    continue
                # 修改alphai与alphaj,注意改变值相同,符号不同
                alphas[j] -= labels_matrix[j] * (ei - ej)/eta
                alphas[j] = clip_alpha(alphas[j], H, L)
                if abs(alphas[j] - alpha_j_old) < 0.00001:
                    print('j not moving enough')
                    continue
                alphas[i] += labels_matrix[j] * labels_matrix[i] * (alpha_j_old - alphas[j])
                # 设置常数项
                b1 = b - ei - labels_matrix[i]*(alphas[i] - alpha_i_old) * \
                               data_matrix[i, :]*data_matrix[i, :].T - \
                     labels_matrix[j]*(alphas[j] - alpha_j_old) * \
                     data_matrix[i, :]*data_matrix[j, :].T
                b2 = b - ej - labels_matrix[i]*(alphas[i] - alpha_i_old) * \
                    data_matrix[i, :]*data_matrix[j, :].T - \
                    labels_matrix[j] * (alphas[j] - alpha_j_old) * \
                    data_matrix[j, :]* data_matrix[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
                alpha_pari_changed += 1
                print('iter:', it, end='')
                print(' i:', i, end='')
                print(' pari changed: ', alpha_pari_changed)

        if alpha_pari_changed == 0:
            it += 1
        else:
            it = 0
        print('iteration number:', it)

    return b, alphas


dataset, labels = load_dataset('SMO/testSet.txt')
# print(dataset)
# print(labels)
b, alphas = smo_simple(dataset, labels, 0.6, 0.001, 40)
print(b)
print(alphas)


猜你喜欢

转载自blog.csdn.net/ll523587181/article/details/78952138