机器学习实战—— Chap06.SVM

本文详细探讨了支持向量机(SVM)的概念,包括最大间隔分类、核函数的使用以及如何通过Python实现SVM。通过对机器学习实战书中第六章的解析,读者将掌握SVM在分类问题中的应用及其优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import matplotlib.pyplot as plt
import numpy as np
import random

"""
Desc:
    读取数据

Parameters:
    fileName - 文件名
    
Returns:
    dataMat - 数据矩阵
    labelMat - 数据标签
"""
def loadDataSet(fileName):
    # 数据矩阵
    dataMat = []
    # 标签向量
    labelMat = []
    # 打开文件
    fr = open(fileName)
    # 逐行读取
    for line in fr.readlines():
        # 去掉每一行首尾的空白符,例如'\n','\r','\t',' '
        # 将每一行内容根据'\t'符进行切片
        lineArr = line.strip().split('\t')
        # 添加数据(100个元素排成一行)
        dataMat.append([float(lineArr[0]), float(lineArr[1])])
        # 添加标签(100个元素排成一行)
        labelMat.append(float(lineArr[2]))
    return dataMat, labelMat


"""
Desc:
    随机选择alpha_j

Parameters:
    i - alpha
    m - alpha参数个数
    
Returns:
    j - 返回选定的数字
"""
def selectJrand(i, m):
    j = i
    while(j == i):
        # uniform()方法将随机生成一个实数,它在[x, y)范围内
        j = int(random.uniform(0, m))
    return j


"""
Desc:
    修剪alpha

Parameters:
    aj - alpha值
    H - alpha上限
    L - alpha下限
    
Returns:
    aj - alpha值
"""
def clipAlpha(aj, H, L):
    if aj > H:
        aj = H
    if L > aj:
        aj = L
    return aj


"""
Desc:
    简化版SMO算法

Parameters:
    dataMatIn - 数据矩阵
    classLabels - 数据标签
    C - 松弛变量
    toler - 容错率
    maxIter - 最大迭代次数
    
Returns:
    None
"""
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
    # 转换为numpy的mat矩阵存储(100,2)
    dataMatrix = np.mat(dataMatIn)
    # 转换为numpy的mat矩阵存储并转置(100,1)
    labelMat = np.mat(classLabels).transpose()
    # 初始化b参数,统计dataMatrix的维度,m:行;n:列
    b = 0
    # 统计dataMatrix的维度,m:100行;n:2列
    m, n = np.shape(dataMatrix)
    # 初始化alpha参数,设为0
    alphas = np.mat(np.zeros((m, 1)))
    # 初始化迭代次数
    iter_num = 0
    # 最多迭代maxIter次
    while(iter_num < maxIter):
        alphaPairsChanged = 0
        for i in range(m):
            # 步骤1:计算误差Ei
            # multiply(a,b)就是个乘法,如果a,b是两个数组,那么对应元素相乘
            # .T为转置
            fxi = float(np.multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[i, :].T)) + b
            # 误差项计算公式
            Ei = 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_j
                j = selectJrand(i, m)
                # 步骤1,计算误差Ej
                fxj = float(np.multiply(alphas, labelMat).T * (dataMatrix * dataMatrix[j, :].T)) + b
                # 误差项计算公式
                Ej = fxj - float(labelMat[j])
                # 保存更新前的alpha值,使用深拷贝(完全拷贝)A深层拷贝为B,A和B是两个独立的个体
                alphaIold = alphas[i].copy()
                alphaJold = alphas[j].copy()
                # 步骤2:计算上下界H和L
                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
                # 步骤3:计算eta
                eta = 2.0 * dataMatrix[i, :] * dataMatrix[j, :].T - dataMatrix[i, :] * dataMatrix[i, :].T - dataMatrix[j, :] * dataMatrix[j, :].T
                if eta >= 0:
                    print("eta>=0")
                    continue
                # 步骤4:更新alpha_j
                alphas[j] -= labelMat[j] * (Ei - Ej) / eta
                # 步骤5:修剪alpha_j
                alphas[j] = clipAlpha(alphas[j], H, L)
                if(abs(alphas[j] - alphaJold) < 0.00001):
                    print("alpha_j变化太小")
                    continue
                # 步骤6:更新alpha_i
                alphas[i] += labelMat[j] * labelMat[i] * (alphaJold - alphas[j])
                # 步骤7:更新b_1和b_2
                b1 = b - Ei - labelMat[i] * (alphas[i] - alphaIold) * dataMatrix[i, :] * dataMatrix[i, :].T - labelMat[j] * (alphas[j] - alphaJold) * dataMatrix[j, :] * dataMatrix[i, :].T
                b2 = 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更新b
                if(0 < alphas[i] < C):
                    b = b1
                elif(0 < alphas[j] < C):
                    b = b2
                else:
                    b = (b1 + b2) / 2.0
                # 统计优化次数
                alphaPairsChanged += 1
                # 打印统计信息
                print("第%d次迭代 样本:%d, alpha优化次数:%d" % (iter_num, i, alphaPairsChanged))
        # 更新迭代次数
        if(alphaPairsChanged == 0):
            iter_num += 1
        else:
            iter_num = 0
        print("迭代次数:%d" % iter_num)
    return b, alphas
                

"""
Desc:
    计算w

Returns:
    dataMat - 数据矩阵
    labelMat - 数据标签
    alphas - alphas值
    
Returns:
    w - 直线法向量
"""
def get_w(dataMat, labelMat, alphas):
    alphas, dataMat, labelMat = np.array(alphas), np.array(dataMat), np.array(labelMat)
    # 我们不知道labelMat的shape属性是多少,
    # 但是想让labelMat变成只有一列,行数不知道多少,
    # 通过labelMat.reshape(1, -1),Numpy自动计算出有100行,
    # 新的数组shape属性为(100, 1)
    # np.tile(labelMat.reshape(1, -1).T, (1, 2))将labelMat扩展为两列(将第1列复制得到第2列)
    # dot()函数是矩阵乘,而*则表示逐个元素相乘
    # w = sum(alpha_i * yi * xi)
    w = np.dot((np.tile(labelMat.reshape(1, -1).T, (1, 2)) * dataMat).T, alphas)
    return w.tolist()


"""
Desc:
    分类结果可视化

Returns:
    dataMat - 数据矩阵
    w - 直线法向量
    b - 直线截距
    
Returns:
    None
"""
def showClassifer(dataMat, w, b):
    # 正样本
    data_plus = []
    # 负样本
    data_minus = [
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值