【无标题】

概念

支持向量机的基本概念,支持向量机是一种二分类模型,在机器学习,计算机视觉,数据挖掘中广泛应用,主要解决数据的分类问题,目的是寻找一个超平面对样本进行分割,分割的原则是间隔最大化。通常SVM用于二元分类问题,对于多元分类可将其分解为多个二元分类问题,再进行分类,支持向量机就是对应着将数据正确划分并且间隔最大的直线。

算法原理

在这里插入图片描述

SVM 算法即寻找一个分类器使得超平面和最近的数 据点之间的分类边缘(超平面和最近的数据点之间的 间隔被称为分类边缘)最大,对于 SVM 算法通常认 为分类边缘越大,平面越优,通常定义具有“最大间 隔”的决策面就是 SVM 要寻找的最优解。并且最优 解对应两侧虚线要穿过的样本点,称为“支持向量”。 其处理的基本思路为:把问题转化为一个凸二次规划 问题,可以用运筹学有关思想进行求解:①目标函数 在线性 SVM 算法中,目标函数显然就是那个"分类间 隔",使分类间隔最大 ②约束条件 即决策面,通常需 要满足三个条件:1)确定决策面使其正确分类 2)决 策面在间隔区域的中轴线 3)如何确定支持向量 因此求解 SVM 问题即转化为求解凸二次规划的最优化问题。

支持向量机就是用来分割数据点那个分割面,他的位置是由支持向量确定的(如果支持 向量发生了变化,往往分割面的位置也会随之改变), 因此这个面就是一个支持向量确定的 分类器即支持向量机。 线性可分数据的二值分类机理:系统随机产生一个超平面并移动它,直到训练集中属于不同类别的样本点正好位于该超平面的两侧。显然,这种机理能够解决线性分类问题,但不能够保证产生的超平面是最优的。支持向量机建立的分类超平面能够在保证分类精度的同时, 使超平面两侧的空白区域最大化,从而实现对线性可分问题的最优分类。
在这里插入图片描述
SVM 的主要思想是:建立一个最优决策超平面,使得该平面两侧距平面最近的两类样 本之间的距离最大化,从而对分类问题提供良好的泛化力(推广能力) “支持向量”:则是指训练集中的某些训练点,这些点最靠近分类决策面,是最难分类的数据点。 SVM:它是一种有监督(有导师)学习方法,即已知训练点的类别,求训练点和类别 之间的对应关系,以便将训练集按照类别分开,或者是预测新的训练点所对应的类别。

代码实现

导入包

import csv
import numpy as np
import matplotlib.pyplot as plt
import copy
from time import sleep
import random
import types


#数据处理


def loadDataset(filename):
    with open(filename, 'r') as f:
        lines = csv.reader(f)
        data_set = list(lines)
    if filename != 'titanic.csv':
        for i in range(len(data_set)):
            del(data_set[i][0])
    # 整理数据
    for i in range(len(data_set)):
        del(data_set[i][0])
        del(data_set[i][2])
        data_set[i][4] += data_set[i][5]
        del(data_set[i][5])
        del(data_set[i][5])
        del(data_set[i][6])
        del(data_set[i][-1])

    category = data_set[0]

    del (data_set[0])
    # 转换数据格式
    for data in data_set:
        data[0] = int(data[0])
        data[1] = int(data[1])
        if data[3] != '':
            data[3] = float(data[3])
        else:
            data[3] = None
        data[4] = float(data[4])
        data[5] = float(data[5])
    # 补全缺失值 转换记录方式 分类
    for data in data_set:
        if data[3] is None:
            data[3] = 28
        # male : 1, female : 0
        if data[2] == 'male':
            data[2] = 1
        else:
            data[2] = 0
# 经过测试,如果不将数据进行以下处理,分布会过于密集,处理后,数据的分布变得稀疏了
        # age <25 为0, 25<=age<31为1,age>=31为2
        if data[3] < 25:
            data[3] = 0
        elif data[3] >= 21 and data[3] < 60: # 但是测试得60分界准确率最高???!!!
            data[3] = 1
        else:
            data[3] = 2
        # sibsp&parcg以2为界限,小于为0,大于为1
        if data[4] < 2:
            data[4] = 0
        else:
            data[4] = 1
        # fare以64为界限
        if data[-1] < 64:
            data[-1] = 0
        else:
            data[-1] = 1


    return data_set, category

def split_data(data):

    data_set = copy.deepcopy(data)

    data_mat = []
    label_mat = []
    for i in range(len(data_set)):
        if data_set[i][0] == 0:
            data_set[i][0] = -1

        label_mat.append(data_set[i][0])
        del(data_set[i][0])
        data_mat.append(data_set[i])

    print(data_mat)
    print(label_mat)

    return data_mat, label_mat

## SVM


def select_j_rand(i ,m):
    # 选取alpha
    j = i
    while j == i:
        j = int(random.uniform(0, m))
    return j
    
def clip_alptha(aj, H, L):
    # 修剪alpha
    if aj > H:
        aj = H
    if L > aj:
        aj = L

    return aj

def smo(data_mat_In, class_label, C, toler, max_iter):
    # 转化为numpy的mat存储
    data_matrix = np.mat(data_mat_In)
    label_mat = np.mat(class_label).transpose()
    # data_matrix = data_mat_In
    # label_mat = class_label
    # 初始化b,统计data_matrix的纬度
    b = 0
    m, n = np.shape(data_matrix)
    # 初始化alpha,设为0
    alphas = np.mat(np.zeros((m, 1)))
    # 初始化迭代次数
    iter_num = 0
    # 最多迭代max_iter次
    while iter_num < max_iter:
        alpha_pairs_changed = 0
        for i in range(m):
            # 计算误差Ei
            fxi = float(np.multiply(alphas, label_mat).T*(data_matrix*data_matrix[i, :].T)) + b
            Ei = fxi - float(label_mat[i])
            # 优化alpha,松弛向量
            if (label_mat[i]*Ei < -toler and alphas[i] < C) or (label_mat[i]*Ei > toler and alphas[i] > 0):
                # 随机选取另一个与alpha_j成对优化的alpha_j
                j = select_j_rand(i, m)
                # 1.计算误差Ej
                fxj = float(np.multiply(alphas, label_mat).T*(data_matrix*data_matrix[j, :].T)) + b
                Ej = fxj - float(label_mat[j])
                # 保存更新前的alpha,deepcopy
                alpha_i_old = copy.deepcopy(alphas[i])
                alpha_j_old = copy.deepcopy(alphas[j])
                # 2.计算上下界L和H
                if label_mat[i] != label_mat[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 * 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
                # 4.更新alpha_j
                alphas[j] -= label_mat[j]*(Ei - Ej)/eta
                # 5.修剪alpha_j
                alphas[j] = clip_alptha(alphas[j], H, L)
                if abs(alphas[j] - alphas[i]) < 0.001:
                    print("alpha_j变化太小")
                    continue
                # 6.更新alpha_i
                alphas[i] += label_mat[j]*label_mat[i]*(alpha_j_old - alphas[j])
                # 7.更新b_1和b_2
                b_1 = b - Ei - label_mat[i]*(alphas[i] - alpha_i_old)*data_matrix[i, :]*data_matrix[i, :].T - label_mat[j]*(alphas[j] - alpha_j_old)*data_matrix[i, :]*data_matrix[j, :].T
                b_2 = b - Ej - label_mat[i]*(alphas[i] - alpha_i_old)*data_matrix[i, :]*data_matrix[j, :].T - label_mat[j]*(alphas[j] - alpha_j_old)*data_matrix[j, :] * data_matrix[j, :].T
                # 8.根据b_1和b_2更新b
                if 0 < alphas[i] and C > alphas[i]:
                    b = b_1
                elif 0 < alphas[j] and C > alphas[j]:
                    b = b_2
                else:
                    b = (b_1 + b_2)/2
                # 统计优化次数
                alpha_pairs_changed += 1
                # 打印统计信息
                print("第%d次迭代 样本:%d , alpha优化次数:%d" % (iter_num, i, alpha_pairs_changed))
        # 更新迭代次数
        if alpha_pairs_changed == 0:
            iter_num += 1
        else:
            iter_num = 0
        print("迭代次数:%d" % iter_num)

    return b, alphas


def caluelate_w(data_mat, label_mat, alphas):
    # 计算w
    alphas = np.array(alphas)
    data_mat = np.array(data_mat)
    label_mat = np.array(label_mat)

    # numpy.tile(A, reps):通过重复A给出的次数来构造数组。

    # numpy中reshape函数的三种常见相关用法
    # reshape(1, -1)转化成1行:
    # reshape(2, -1)转换成两行:
    # reshape(-1, 1)转换成1列:
    # reshape(-1, 2)转化成两列

    w = np.dot((np.tile(label_mat.reshape(1, -1).T, (1, 5))*data_mat).T, alphas)
    return w.tolist()

## 主程序

if __name__ == "__main__":
    test_set, category = loadDataset('titanic_test.csv')
    data_set, category = loadDataset('titanic_train.csv')

    test_mat, test_label = split_data(test_set)
    data_mat, label_mat = split_data(data_set)

    b, alphas = smo(data_mat, list(label_mat), 0.6, 0.001, 40)
    print(b)
    print(alphas)
    w = caluelate_w(data_mat, label_mat, alphas)
    print(w)

    print(test_mat)
    print(test_label)
    result = prediction(test_mat, w, b)

    count = 0
    for i in range(len(result)):
        if result[i] == test_label[i]:
            count += 1

    print(count)

    print(f'the accuracy is {count/len(result)}')

测试结果

在这里插入图片描述

优缺点

优点
1.SVM是一种有坚实理论基础的传统机器学习方法。它基本上不涉及概率测度及大数定律等,也对通常的回归与分类问题做了简化。

2.由于使用了核函数,使得其计算的复杂性取决于支持向量的数目,而不是样本空间的维数,这在某种意义上避免了“维数灾难”。

3.少数支持向量决定了最终结果,对异常值不敏感, 这不但可以帮助我们抓住关键样本、“剔除”大量冗余样本,而且注定了该方法不但算法简单,而且具有较好的“鲁棒性”.

缺点
1.支持向量机算法对大规模训练样本难以实施,这是因为支持向量算法借助二次规划求解支持向量,这其中会设计m阶矩阵的计算,所以矩阵阶数很大时将耗费大量的机器内存和运算时间。

2.经典的SVM只给出二分类的算法,而在数据挖掘中,一般要解决多分类的分类问题,而支持向量机对于多分类问题解决效果并不理想。

3.现在常用的SVM理论都是使用固定惩罚系数C,但是正负样本的两种错误造成的损失是不一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值