机器学习——支持向量机

线性可分支持向量机

泛化性

先来了解一下什么叫泛化性?我们要求一条直线不仅要在训练集(已知的数据)上能够很好的将数据分类好,还得在测试集(未知的数据)上也能很好的完成。
在这里插入图片描述
那现在我们来看看图中的两条直线,哪一条的泛化性更好呢?
在这里插入图片描述

假设经过训练,我们得到黄色这条决策边界来区分我们的数据,这个时候出现一个黑色的数据点,现在对它进行分类,你认为它会被分到哪一类呢?
根据图像它会被分到红色这类中,但是我们可以看出它离蓝色点相较于离红色点来说近得多,因此它应该是属于蓝色点的。这就说明了这条直线的泛化性并不好,它对于未知的数据并不能很好的进行分类。

基本思想

那如何得到一条泛化性较好的直线呢?这个时候我们就要使用支持向量机去思考这个问题了。
支持向量机要一条决策边界有较好的泛化性,它需要满足:① 能很好的将样本划分;② 离最近的样本点最远
在这里插入图片描述
现在来看看这条黑线,它可以很正确的将两种点区分开,最重要的是它还保证了未知样本的容错率,因为它离最近的红点和蓝点都较远,这时再有一个数据点,就不会出现之前黄色边界的错误了。
在这里插入图片描述
无论新的数据出现在哪个位置,黑色的决策边界都能够很好的给它进行分类,这个就是支持向量机的基本思想。

间隔与向量机

在样本空间种,我们通常使用下面的线性方程来描述决策边界:在这里插入图片描述
其中
在这里插入图片描述
为法向量,决定了决策边界的方向,b为位移项,决定了决策边界与原点之间的距离。显然,决策边界可以被法向量和位移确定,我们将其表示为(w,b)。样本种的任意一个点,到决策边界(w,b)的距离为:在这里插入图片描述
假设决策边界(w,b)能够将训练样本正确分类,即对于任何一个样本点(xi,yi),若它为正类,即yi=+1时,wTx+b≥+1 ,若为负类,即yi=-1时,wTx+b≤−1。
在这里插入图片描述
若距离最近的几个点使两个不等式的等号成立,那它们就称为支持向量机,即图中的两条黄色的线,两个异类支持向量机到平面的距离之和为在这里插入图片描述
它被称为间隔,即蓝线的长度,想要找到具有最大间隔的决策边界,即黑色的线,也就是要找到能够同时满足如下式子的w与b:
在这里插入图片描述

软间隔最大化

上面有说到黄色的线的泛化性不太好,造成这样结果的原因是数据中存在着异常点,支持向量机引入了软间隔最大化的方法来解决这个问题。所谓软间隔是相对于硬间隔而言的,SVM对训练集里面的每个样本(xi,yi)引入了一个松弛变量xi≥0,使函数间隔加上松驰变量大于等于1,也就是说:
在这里插入图片描述
对比硬间隔最大化,可以看懂我们对样本到超平面的函数距离的要求放松了,之前是一定要大于等于1,现在只需要加上一个大于等于0的松弛变量能大于等于1就可以了。也就是允许支持向量机在一些样本上出错,允许有一定的容错率。
在这里插入图片描述
机器学习中使用sklearn中提供的方法来提供支持向量机分类器,from sklearn.svm import LinearSVC

from sklearn.svm import LinearSVC

def linearsvc_predict(train_data,train_label,test_data):
    '''
    input:train_data(ndarray):训练数据
          train_label(ndarray):训练标签
    output:predict(ndarray):测试集预测标签
    '''
    # 回归器
    clf = LinearSVC(dual=False)
    clf.fit(train_data,train_label)
    # 预测
    predict = clf.predict(test_data)

    return predict

非线性支持向量机

在这里插入图片描述
再来看看这组数据,我们的数据集有时候是非线性可分的情况。对于非线性的情况,SVM的处理方式就是选择一个核函数,(简单来说核函数就是将低维的数据集变为高维的,这样是为了解决化简一些在低维空间无法形成线性关系的数据集,将它们映射到高维空间中,便与训练数据),SVM通过某种事先选择的非线性映射将输入变量映射到一个高维特征空间,将其变成在高维空间线性可分,在这个高维空间中构造最优分类超平面,例如:
在这里插入图片描述
sklearn中依旧提供了方法用于解决非线性的问题,依旧提供核函数

#encoding=utf8
from sklearn.svm import SVC
def svc_predict(train_data,train_label,test_data,kernel):
    '''
    input:train_data(ndarray):训练数据
          train_label(ndarray):训练标签
          kernel(str):使用核函数类型:
              'linear':线性核函数
              'poly':多项式核函数
              'rbf':径像核函数/高斯核
    output:predict(ndarray):测试集预测标签
    '''
    clf = SVC(kernel=kernel)
    clf.fit(train_data,train_label)
    predict = clf.predict(test_data) 
    return predict

序列最小优化算法

smo算法基本思想
支持向量机的学习问题可以形式化为求解凸二次规划问题。这样的凸二次规划问题具有全局最优解,并且有许多最优化算法可以用于这一问题的求解。但是当训练样本容量很大时,这些算法往往变得非常低效,以致于无法使用。所以,如何高效地实现支持向量机学习就成为一个重要的问题,目前最具代表的快速实现算法是序列最小优化算法(smo)
smo算法要解如下凸二次规划的对偶问题:
在这里插入图片描述
smo算法是一种启发式算法,基本思路是如果所有变量的解都满足此最优化问题的KTT条件,那么这个最优化问题的解就得到了。因为KTT条件是该最优化问题的充要条件。否则选择两个变量,固定其他变量,针对着两个变量构建一个二次规划问题。这个二次规划问题关于这两个变量的解应该更接近原始二次规划问题的解,因为这会使原始二次规划问题的目标函数值变得更小。重要的是这时子问题可以通过解析方法求解,这样就可以大大提高整个算法的计算速度。子问题有两个变量,一个是违反KTT条件最严重的那一个,另一个由约束条件自动确定。如此,smo算法将原问题不断分解为子问题并对子问题求解,进而达到求解原问题的目的。
优化
为了求解上面含有这两个变量的目标优化问题,我们首先分析约束条件,所有的alpha1 ,alpha2​ 都要满足约束条件,然后在约束条件下求最小。


#encoding=utf8
import numpy as np
class smo:
    def __init__(self, max_iter=100, kernel='linear'):
        '''
        input:max_iter(int):最大训练轮数
              kernel(str):核函数,等于'linear'表示线性,等于'poly'表示多项式
        '''
        self.max_iter = max_iter
        self._kernel = kernel
    #初始化模型
    def init_args(self, features, labels):
        self.m, self.n = features.shape
        self.X = features
        self.Y = labels
        self.b = 0.0
        # 将Ei保存在一个列表里
        self.alpha = np.ones(self.m)
        self.E = [self._E(i) for i in range(self.m)]
        # 错误惩罚参数
        self.C = 1.0 
    #kkt条件    
    def _KKT(self, i):
        y_g = self._g(i)*self.Y[i]
        if self.alpha[i] == 0:
            return y_g >= 1
        elif 0 < self.alpha[i] < self.C:
            return y_g == 1
        else:
            return y_g <= 1
    # g(x)预测值,输入xi(X[i])
    def _g(self, i):
        r = self.b
        for j in range(self.m):
            r += self.alpha[j]*self.Y[j]*self.kernel(self.X[i], self.X[j])
        return r
    # 核函数,多项式添加二次项即可
    def kernel(self, x1, x2):
        if self._kernel == 'linear':
            return sum([x1[k]*x2[k] for k in range(self.n)])
        elif self._kernel == 'poly':
            return (sum([x1[k]*x2[k] for k in range(self.n)]) + 1)**2    
        return 0
    # E(x)为g(x)对输入x的预测值和y的差
    def _E(self, i):
        return self._g(i) - self.Y[i]
    #初始alpha
    def _init_alpha(self):
        # 外层循环首先遍历所有满足0<a<C的样本点,检验是否满足KKT
        index_list = [i for i in range(self.m) if 0 < self.alpha[i] < self.C]
        # 否则遍历整个训练集
        non_satisfy_list = [i for i in range(self.m) if i not in index_list]
        index_list.extend(non_satisfy_list)
        for i in index_list:
            if self._KKT(i):
                continue
            E1 = self.E[i]
            # 如果E2是+,选择最小的;如果E2是负的,选择最大的
            if E1 >= 0:
                j = min(range(self.m), key=lambda x: self.E[x])
            else:
                j = max(range(self.m), key=lambda x: self.E[x])
            return i, j
    #选择alpha参数   
    def _compare(self, _alpha, L, H):
        if _alpha > H:
            return H
        elif _alpha < L:
            return L
        else:
            return _alpha
    #训练
    def fit(self, features, labels):
        '''
        input:features(ndarray):特征
              label(ndarray):标签
        '''
        self.init_args(features, labels)
        for t in range(self.max_iter):
            i1, i2 = self._init_alpha()
            # 边界
            if self.Y[i1] == self.Y[i2]:
                L = max(0, self.alpha[i1]+self.alpha[i2]-self.C)
                H = min(self.C, self.alpha[i1]+self.alpha[i2])
            else:
                L = max(0, self.alpha[i2]-self.alpha[i1])
                H = min(self.C, self.C+self.alpha[i2]-self.alpha[i1])
            E1 = self.E[i1]
            E2 = self.E[i2]
            # eta=K11+K22-2K12
            eta = self.kernel(self.X[i1], self.X[i1]) + self.kernel(self.X[i2], self.X[i2]) - 2*self.kernel(self.X[i1], self.X[i2])
            if eta <= 0:
                continue
            alpha2_new_unc = self.alpha[i2] + self.Y[i2] * (E2 - E1) / eta
            alpha2_new = self._compare(alpha2_new_unc, L, H)
            alpha1_new = self.alpha[i1] + self.Y[i1] * self.Y[i2] * (self.alpha[i2] - alpha2_new)
            b1_new = -E1 - self.Y[i1] * self.kernel(self.X[i1], self.X[i1]) * (alpha1_new-self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i1]) * (alpha2_new-self.alpha[i2])+ self.b 
            b2_new = -E2 - self.Y[i1] * self.kernel(self.X[i1], self.X[i2]) * (alpha1_new-self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i2]) * (alpha2_new-self.alpha[i2])+ self.b 
            if 0 < alpha1_new < self.C:
                b_new = b1_new
            elif 0 < alpha2_new < self.C:
                b_new = b2_new
            else:
                # 选择中点
                b_new = (b1_new + b2_new) / 2
            # 更新参数
            self.alpha[i1] = alpha1_new
            self.alpha[i2] = alpha2_new
            self.b = b_new
            self.E[i1] = self._E(i1)
            self.E[i2] = self._E(i2)       
    def predict(self, data):
        '''
        input:data(ndarray):单个样本
        output:预测为正样本返回+1,负样本返回-1
        '''
        r = self.b
        for i in range(self.m):
            r += self.alpha[i] * self.Y[i] * self.kernel(data, self.X[i])
        return 1 if r > 0 else -1

来源:头歌

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
支持向量机(Support Vector Machine, SVM)的算法步骤如下: 1. 收集训练样本集,并将每个样本表示为特征向量。每个特征向量可以是M维的向量,其M为特征的数量。 2. 选择一个合适的核函数或非线性变换方式,将原始特征空间映射到一个更高维的特征空间。这个变换可以使线性不可分的样本集变为线性可分。 3. 基于训练样本集,建立一个支持向量机模型。该模型的目标是找到一个超平面,能够最大化样本间的间隔并且正确地分类样本。间隔是指支持向量与超平面之间的距离。 4. 通过求解优化问题,确定超平面的参数。优化问题的目标是最小化模型的结构风险,同时最大化间隔。这可以通过使用拉格朗日乘子法和KKT条件来实现。 5. 根据优化问题的解,确定支持向量,即位于间隔边界上的样本。这些样本对于模型的构建和分类起到关键作用。 6. 对于新的未知样本,使用训练好的模型进行分类。通过计算样本到超平面的距离,确定样本属于哪个类别。 总结起来,支持向量机的算法步骤包括收集训练样本集、选择合适的核函数或非线性变换方式、建立模型、确定超平面的参数、确定支持向量,最后使用模型进行分类。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [机器学习——支持向量机](https://blog.csdn.net/weixin_55252589/article/details/122688871)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值