SVM基本实现看这一篇就够啦

1.什么是SVM?

        

        SVM(支持向量机)是一种常见的监督学习算法,用于分类和回归问题。在分类问题中,SVM通过在特征空间中找到一个最优的超平面来将不同类别的数据分隔开。在回归问题中,SVM通过寻找一个最优的超平面来拟合数据点,使得尽可能多的数据点位于超平面的边界上。

        SVM的核心思想是将原始特征映射到一个高维特征空间,并在该空间中找到一个最优的超平面。为了找到最优的超平面,SVM采用了两个关键概念:间隔和支持向量。间隔表示超平面到最近的训练样本的距离,SVM的目标是找到具有最大间隔的超平面。支持向量是离超平面最近的训练样本点,它们对于定义超平面起到关键作用。

        SVM算法可以使用不同的核函数,如线性核、多项式核和高斯核,来处理非线性的分类问题。这些核函数可以将数据从原始特征空间映射到一个更高维的特征空间,在新的特征空间中进行线性分类或回归。

2.如何算点到超平面的距离?

        

   

     这两个的r和d是一样的只是表示的形式有点区别

    如上图,这里举个简单的例子:有个平面2x+2y+2z = 0    (看到wT不用害怕只是换个方向)

3.判断正例还是负

这里简单说一下 2 / |w| 如何来的

+ 号 到 平面的距离 (W^T + b - 1)/|w|

- 号 到 平面的距离(W^T + b + 1)/ |w| 

两者 的距离就是 2 / |w|

4.如何确定平面?

     1.   这里采用代码和附上数学原理解答,先上代码
    def __init__(self, learning_rate=0.002, lambda_param=8, n_iters=10000):
        self.lr = learning_rate#学习率
        self.lambda_param = lambda_param#正则化参数
        self.n_iters = n_iters#训练次数
        self.w = None#权重   
        self.b = None    
        
        def fit(self, X, y):
        y_ = np.where(y <= 0, -1, 1)
        n_samples, n_features = X.shape

        self.w = np.zeros(n_features)
        self.b = 0

        for _ in range(self.n_iters):
            for idx, x_i in enumerate(X):#返回(idx,x)
                condition = y_[idx] * (np.dot(x_i, self.w) - self.b) >= 1
                if condition:
                    self. w -= self.lr * (2 * self.lambda_param * self.w)
                else:
                    self.w -= self.lr * (2 * self.lambda_param * self.w - np.dot(x_i, y_[idx]))
                    self.b -= self.lr * y_[idx]

 这里面的公式是如何来的呢? 由上面的推导我们需要找到2/w 的 最大值  ,所以等价于找 w的最小值,也可以等价于 找1/2 w^2的最小值

      condition = y_[idx] * (np.dot(x_i, self.w) - self.b) >= 1 #判断是否对样本判断正确

       接下来的重点放在解释self. w -= self.lr * (2 * self.lambda_param * self.w) 这个梯度下降的公式是如何来的

        2.公式如何来?

                在上面的红色字体中我们知道 求解 1/2 w^2是最后的目标,但是在样本中难免存在噪声,和一些离谱的情况导致哪怕 找到一个很好的平面还是会有一两个样本点鹤立独行在 分类的另外一边,所以我采用正则化的梯度下降来解决

        3.什么是正则化?正则化有什么用?

        

        正则化是一种常用的机器学习技术,用于控制模型的复杂度和泛化能力。正则化通过添加一个惩罚项到模型的目标函数中,来避免过拟合问题,即在训练集上表现很好,但在测试集上表现较差的情况。

        在机器学习中,我们通常会通过最小化目标函数来得到一个最优的模型,其中目标函数包含了误差项和正则化项。误差项用来衡量模型对训练数据的拟合程度,而正则化项则用来约束模型的复杂度。

        正则化可以分为 L1 正则化和 L2 正则化两种形式。L1 正则化会使得一部分权重变为 0,因此可以实现特征选择的功能,从而减少模型的复杂度。L2 正则化则会使得权重向量的每个元素都变得较小,从而避免过拟合。

        使用正则化的主要原因是为了避免模型过拟合,提高模型的泛化能力。过拟合是指模型过于复杂,导致在训练集上表现很好,但在测试集上表现较差的情况。正则化的作用就是通过限制模型的复杂度,来避免过拟合问题,从而提高模型的泛化能力。

        另外,正则化也有一定的优化作用。在某些情况下,添加正则化项到目标函数中可以使得模  型更容易被训练,收敛速度更快,同时还可以改善模型的数值稳定性。

        4.梯度下降

     由于我使用的梯度下降的策略实现SVM分类所以要选择相对于的目标函数:我这边选择的是

        

        其中λ就是正则化参数,通过调节参数避免过拟合。他的作用是对于后面一个多项式而言其中1/N作为归一化因子,将误差平均化更好的反映数据集的情况,

当1 - y_i * (w^T * x_i - b) 大于等于 0,意味着样本点 x_i 被正确分类或位于决策边界上。这时损失函数的值为 0。

 1 - y_i * (w^T * x_i - b) 小于 0,意味着样本点 x_i 被错误分类到了决策边界的错误一侧。这时损失函数的值大于 0,表示样本点被错误分类。

如果样本被正确分类(y_i * (w^T * x_i - b) >= 1),则梯度为 2 * λ * w。
如果样本被错误分类(y_i * (w^T * x_i - b) < 1),则梯度为 2 * λ * w - y_i * x_i。 

5.运行结果

λ = 0.002   

        

 λ = 2 

6.完整代码

        

import numpy as np
import matplotlib.pyplot as plt


class SVM:
    def __init__(self, learning_rate=0.002, lambda_param=0, n_iters=1000):
        self.lr = learning_rate
        self.lambda_param = lambda_param
        self.n_iters = n_iters
        self.w = None
        self.b = None

    def fit(self, X, y):
        y_ = np.where(y <= 0, -1, 1)
        n_samples, n_features = X.shape

        self.w = np.zeros(n_features)
        self.b = 0

        for _ in range(self.n_iters):
            for idx, x_i in enumerate(X):#返回(idx,x)
                condition = y_[idx] * (np.dot(x_i, self.w) - self.b) >= 1
                print(idx,condition)
                if condition:
                    self. w -= self.lr * (2 * self.lambda_param * self.w)
                else:
                    self.w -= self.lr * (2 * self.lambda_param * self.w - np.dot(x_i, y_[idx]))
                    self.b -= self.lr * y_[idx]

    def predict(self, X):
        linear_output = np.dot(X, self.w) - self.b
        return np.sign(linear_output)


def plot_decision_boundary(X, y, svm):
    x1 = np.linspace(np.min(X[:, 0]) - 1, np.max(X[:, 0]) + 1, 100)
    x2 = np.linspace(np.min(X[:, 1]) - 1, np.max(X[:, 1]) + 1, 100)
    xx1, xx2 = np.meshgrid(x1, x2)
    grid = np.c_[xx1.ravel(), xx2.ravel()]
    pred = svm.predict(grid)
    pred = pred.reshape(xx1.shape)

    plt.contourf(xx1, xx2, pred, alpha=0.8, cmap=plt.cm.Paired)
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired)
    plt.xlabel("X1")
    plt.ylabel("X2")
    plt.title("SVM Decision Boundary")
    plt.show()


# 测试代码
X = np.array(
    [[1, 2], [2, 3], [4, 5], [6, 7], [32, 56], [12, 98], [45, 23], [78, 11], [29, 45], [67, 89], [54, 34], [98, 76],
     [11, 65], [87, 99]])
y = np.array([-1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1])

svm = SVM()
svm.fit(X, y)

# 打印训练后的参数
print("w: ", svm.w)
print("b: ", svm.b)

# 预测新数据
new_X = np.array([
    [80, 82],
    [5, 3]
])
print("Predictions: ", svm.predict(new_X))

# 绘制决策边界
plot_decision_boundary(X, y, svm)

7.总结

        在学SVM的时候前后看到了许多实现的办法,其中用梯度下降的办法算是比较好理解的,其中用拉格朗日乘子法求解的并没有搞的很懂,只推导到了下面这一步。

 然后得出了KKT的条件,就不知道怎么往下了。求大佬教教😍😍😍

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值