机器学习:支持向量机

news2025/1/30 15:58:27

支持向量机(Support Vector Machine)是一种二类分类模型,其基本模型定义为特征空间上的间隔最大的广义线性分类器,其学习策略便是间隔最大化,最终可转化为一个凸二次规划问题的求解。

在这里插入图片描述

假设两类数据可以被 H = x : w T x + b ≥ c H = {x:w^Tx + b \ge c} H=x:wTx+bc分离,垂直于法向量 w w w,移动 H H H直到碰到某个训练点,可以得到两个超平面 H 1 H_1 H1 H 2 H_2 H2,两个平面称为支撑超平面,题目分别支撑两类数据。而位于 H 1 H_1 H1 H 2 H_2 H2正中间的超平面是分离这两类数据的最好选择。支持向量就是离分隔超平面最近的那些点。

法向量 w w w有很多种选择,超平面 H 1 H_1 H1 H 2 H_2 H2之间的距离称为间隔,这个间隔是 w w w的函数,**目的就是寻找这样的 w w w使得间隔达到最大。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在求解最优化问题中,拉格朗日乘子法(Lagrange Multiplier)和KKT(Karush Kuhn Tucker)条件是两种最常用的方法。在有等式约束时使用拉格朗日乘子法,在有不等约束时使用KKT条件。

  • 拉格朗日乘子法

    拉格朗日乘子法是一种寻找多元函数在一组约束下的极值的方法。通过引入拉格朗日乘子,可将有 d d d个变量与 k k k个约束条件的最优化问题转化为具有 d + k d+k d+k个变量的无约束优化问题求解。

  • 二次规划

    二次规划是一类典型的优化问题,包括凸二次优化和非凸二次优化。在此类问题中,目标函数是变量的二次函数,而约束条件是变量的线性不等式。
    m i n 1 2 x T Q x + c T x s . t . A ⃗ x ⃗ ≤ b ⃗ min \frac{1} {2} x^T Q x + c^T x \\ s.t. \vec{A} \vec{x} \le \vec{b} min21xTQx+cTxs.t.A x b

具体公式证明:【整理】深入理解拉格朗日乘子法(Lagrange Multiplier) 和KKT条件 - mo_wang - 博客园 (cnblogs.com)

序列最小优化(Sequential Minimal Optimization,SMO)

序列最小优化是将大优化问题分界成多个小优化问题来求解。

SMO算法工作原理:每次循环中选择两个变量进行优化处理。一旦找到一对合适的变量,那么就增大其中一个同时减小另一个。这里的“合适”指的是两个变量必须要符合一定的条件,条件之一就是这两个变量必须要在间隔边界之外,而其第二个条件则是这两个变量还没有进行过区间化处理或者不在边界上。

在这里插入图片描述

代码实现

参考《机器学习实战》,代码链接:https://github.com/golitter/Decoding-ML-Top10/tree/master/SVM

这里采用简化的SMO代码,数据集是https://blog.caiyongji.com/assets/mouse_viral_study.csv。

data_processing.py

import numpy as np
import pandas as pd

# https://zhuanlan.zhihu.com/p/350836534
def data_processing():
    data_csv = pd.read_csv('mouse_viral_study.csv')
    data_csv = data_csv.dropna()
    # print(data_csv)
    X = data_csv.iloc[:-1, 0:2].values
    # print(X)
    Y = data_csv.iloc[:-1, 2].map({0: -1, 1: 1}).values
    Y = Y.reshape(-1, 1)
    # print(Y.shape)
    return X, Y

# X, Y = data_processing()
# print(X)

工具模块,smo_assist.py

import random
def select_Jrandom(i:int, m:int) -> int:
    """
    随机选择一个不等于 i 的整数
    """
    j = i
    while j == i:
        j = int(random.uniform(0, m))
    return j

def clip_alpha(alpha_j:float, H:float, L:float) -> float:
    """
    修剪 alpha_j
    """
    if alpha_j > H:
        alpha_j = H
    if alpha_j < L:
        alpha_j = L
    return alpha_j

简化SMO的代码实现,smoSimple.py

from smo_assist import (
    select_Jrandom, 
    clip_alpha)

import numpy as np
import pdb

def smoSimple(data_mat_in:np.ndarray, class_labels:np.ndarray, C:float, toler:float, max_iter:int):
    """
    data_mat_in: 数据集
    class_labels: 类别标签
    C: 松弛变量
    toler: 容错率
    max_iter: 最大迭代次数
    """
    b = 0; # 初始化b
    m, n = np.shape(data_mat_in) # m: 样本数, n: 特征数
    alphas = np.zeros((m, 1)) # 初始化alpha
    iter = 0 # 迭代次数
    while iter < max_iter:
        alphaPairsChanged = 0
        for i in range(m):
            fXi = float(np.multiply(alphas, class_labels).T @ (data_mat_in @ data_mat_in[i, :].T)) + b
            """
             (1 , m) * (m, n) * (n, 1) = (1, 1) = 标量
                再 加上 b 就是 f(x) 的值
            """
            Ei = fXi - float(class_labels[i])
            """
            Ei = f(x) - y 预测误差
            """
            if (
                # 第一种情况:样本被误分类,且权重可以增加
                ((class_labels[i] * Ei < -toler) # 预测误差与标签方向相反,且误差大于容忍度
                  and (alphas[i] < C)) # 当前权重小于正则化参数 C,可以增加权重
                or 
                # 第二种情况:样本被误分类,且权重需要调整
                 ((class_labels[i] * Ei > toler) # 预测误差与标签方向相同,且误差大于容忍度
                   and (alphas[i] > 0)) # 当前权重大于 0,需要调整权重
                ):
                j = select_Jrandom(i, m)
                fxj = float(np.multiply(alphas, class_labels).T @ (data_mat_in @ data_mat_in[j, :].T)) + b
                Ej = fxj - float(class_labels[j])
                alpha_j_old = alphas[j].copy(); 
                alpha_i_old = alphas[i].copy()

                if (class_labels[i] != class_labels[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: 
                    continue # 跳出本次循环
                
                eta = 2.0 * data_mat_in[i, :] @ data_mat_in[j, :].T - data_mat_in[i, :] @ data_mat_in[i, :].T - data_mat_in[j, :] @ data_mat_in[j, :].T
                """
                计算 eta = K11 + K22 - 2 * K12 = 2 * x_i * x_j - x_i * x_i - x_j * x_j 
                """     
                if eta >= 0:
                    continue
                alphas[j] -= class_labels[j] * (Ei - Ej) / eta # 更新权重
                alphas[j] = clip_alpha(alphas[j], H, L) # 调整权重
                if abs(alphas[j] - alpha_j_old) < 0.00001:
                    continue # 跳出本次循环,不更新 i
                alphas[i] += class_labels[j] * class_labels[i] * (alpha_j_old - alphas[j]) # 更新权重
                b1 = b - Ei - class_labels[i] * (alphas[i] - alpha_i_old) * data_mat_in[i, :] @ data_mat_in[i, :].T - class_labels[j] *(alphas[j] - alpha_j_old) * data_mat_in[i, :] @ data_mat_in[j, :].T
                b2 = b - Ej - class_labels[i] * (alphas[i] - alpha_i_old) * data_mat_in[i, :] @ data_mat_in[j, :].T - class_labels[j] *(alphas[j] - alpha_j_old) * data_mat_in[j, :] @ data_mat_in[j, :].T
                """
                更新 b
                """     
                if 0 < alphas[i] < C:
                    b = b1
                elif 0 < alphas[j] < C:
                    b = b2
                else:
                    b = (b1 + b2) / 2.0
                alphaPairsChanged += 1
        if alphaPairsChanged == 0:
            iter += 1
        else:
            iter = 0
    return b, alphas



if __name__ == '__main__':
    print(  smoSimple(np.array([[1, 2], [3, 4]]), np.array([[-1],[1]]), 0.6, 0.001, 40))

test.py

from data_processing import *
from smoSimple import *
import numpy as np
import matplotlib.pyplot as plt

# 数据处理和 SVM 训练
data_mat_in, class_labels = data_processing()
b, alphas = smoSimple(data_mat_in, class_labels, 0.6, 0.001, 40)

# 打印结果
print("Bias (b):", b)
print("Non-zero alphas:", alphas[alphas > 0])

# 打印数据形状
print("Shape of data_mat_in:", np.shape(data_mat_in))
print("Shape of class_labels:", np.shape(class_labels))

# 将 Y 转换为一维数组(如果它是二维的)
Y = class_labels
# 提取不同类别的索引
class_1_indices = np.where(Y == 1)[0]  # 类别为 1 的样本索引
class_2_indices = np.where(Y == -1)[0]  # 类别为 -1 的样本索引
X = data_mat_in

# 绘制散点图
plt.figure(figsize=(8, 6))
plt.scatter(X[class_1_indices, 0], X[class_1_indices, 1], c='blue', label='Class 1', alpha=0.5)
plt.scatter(X[class_2_indices, 0], X[class_2_indices, 1], c='red', label='Class -1', alpha=0.5)

# 计算权重向量 w
w = np.dot((alphas * Y).T, X).flatten()
# print(f"w: {w}")
print("Shape of X:", X.shape)  # 应该是 (m, n)
print("Shape of Y:", Y.shape)  # 应该是 (m, 1)
print("Shape of alphas:", alphas.shape)  # 应该是 (m, 1)

# 绘制超平面
# 超平面方程:w[0] * x1 + w[1] * x2 + b = 0
# 解出 x2: x2 = -(w[0] * x1 + b) / w[1]
x1 = np.linspace(np.min(X[:, 0]), np.max(X[:, 0]), 100)
x2 = -(w[0] * x1 + b) / w[1]
print(f"w_shape: {w.shape}")
# 绘制超平面
plt.plot(x1, x2, label='SVM Hyperplane', color='green', linewidth=2)

# 标出支持向量
support_vectors_indices = np.where(alphas > 0)[0]  # 找到所有支持向量的索引
plt.scatter(X[support_vectors_indices, 0], X[support_vectors_indices, 1], 
            facecolors='none', edgecolors='k', s=50, label='Support Vectors')

# 添加图例和标签
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.title('Scatter Plot of Data with SVM Hyperplane')
plt.legend()

# 显示图形
plt.show()

在这里插入图片描述

ML_AI_SourceCode-/支持向量机 at master · sjyttkl/ML_AI_SourceCode- (github.com)

机器学习:支持向量机(SVM)-CSDN博客

【整理】深入理解拉格朗日乘子法(Lagrange Multiplier) 和KKT条件 - mo_wang - 博客园 (cnblogs.com)

机器学习(四):通俗理解支持向量机SVM及代码实践 - 知乎 (zhihu.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2284184.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot(6)解决ruoyi框架连续快速发送post请求时,弹出“数据正在处理,请勿重复提交”提醒的问题

一、整个前言 在基于 Ruoyi 框架进行系统开发的过程中&#xff0c;我们常常会遇到各种有趣且具有挑战性的问题。今天&#xff0c;我们就来深入探讨一个在实际开发中较为常见的问题&#xff1a;当连续快速发送 Post 请求时&#xff0c;前端会弹出 “数据正在处理&#xff0c;请…

2023年版本IDEA复制项目并修改端口号和运行内存

2023年版本IDEA复制项目并修改端口号和运行内存 1 在idea中打开server面板&#xff0c;在server面板中选择需要复制的项目右键&#xff0c;点击弹出来的”复制配置…&#xff08;Edit Configuration…&#xff09;“。如果idea上没有server面板或者有server面板但没有springbo…

微信小程序怎么制作自己的小程序?手把手带你入门(适合新手小白观看)

对于初学者来说&#xff0c;制作一款微信小程序总感觉高大上&#xff0c;又害怕学不会。不过&#xff0c;今天我就用最简单、最有耐心的方式&#xff0c;一步一步给大家讲清楚!让你知道微信小程序的制作&#xff0c;居然可以这么轻松(希望你别吓跑啊!)。文中还加了实战经验&…

EventBus事件总线的使用以及优缺点

EventBus EventBus &#xff08;事件总线&#xff09;是一种组件通信方法&#xff0c;基于发布/订阅模式&#xff0c;能够实现业务代码解耦&#xff0c;提高开发效率 发布/订阅模式 发布/订阅模式是一种设计模式&#xff0c;当一个对象的状态发生变化时&#xff0c;所有依赖…

vim如何设置自动缩进

:set autoindent 设置自动缩进 :set noautoindent 取消自动缩进 &#xff08;vim如何使设置自动缩进永久生效&#xff1a;vim如何使相关设置永久生效-CSDN博客&#xff09;

LongLoRA:高效扩展大语言模型上下文长度的微调方法

论文地址&#xff1a;https://arxiv.org/abs/2309.12307 github地址&#xff1a;https://github.com/dvlab-research/LongLoRA 1. 背景与挑战 大语言模型&#xff08;LLMs&#xff09;通常在预定义的上下文长度下进行训练&#xff0c;例如 LLaMA 的 2048 个 token 和 Llama2 的…

NoSQL使用详解

文章目录 NoSQL使用详解一、引言二、NoSQL数据库的基本概念三、NoSQL数据库的分类及使用场景1. 键值存储数据库示例代码&#xff08;Redis&#xff09;&#xff1a; 2. 文档存储数据库示例代码&#xff08;MongoDB&#xff09;&#xff1a; 3. 列存储数据库4. 图数据库 四、使用…

《FreqMamba: 从频率角度审视图像去雨问题》学习笔记

paper&#xff1a;FreqMamba: Viewing Mamba from a Frequency Perspective for Image Deraining GitHub&#xff1a;GitHub - aSleepyTree/FreqMamba 目录 摘要 1、介绍 2、相关工作 2.1 图像去雨 2.2 频率分析 2.3 状态空间模型 3、方法 3.1 动机 3.2 预备知识 3…

试用ChatGPT开发一个大语言模型聊天App

参考官方文档&#xff0c;安装android studio https://developer.android.com/studio/install?hlzh-cn 参考这个添加permission权限&#xff1a; https://blog.csdn.net/qingye_love/article/details/14452863 参考下面链接完成Android Studio 给项目添加 gradle 依赖 ht…

第30周:文献阅读

目录 摘要 Abstract 文献阅读 问题引入 方法论 堆叠集成模型 深度学习模型 创新点 堆叠模型 敏感性和不确定性分析 优化模型 实验研究 数据集 水质指数WQI的计算 模型的构建与训练 模型性能评估 敏感性和不确定性分析 结论 摘要 本文聚焦于利用深度学习算…

The just sharing principle: advice for advice givers

原文 A while ago I wrote about how Only you know what’s best for your application. That’s because only you fully understand the context within which you are making technical decisions. Any advice need to filtered through that context in order to determi…

【PVE】PVE部署磁盘阵列

什么是磁盘阵列&#xff1f; 磁盘阵列是一种存储技术&#xff0c;通过将多个物理磁盘组合成一个逻辑存储单元&#xff0c;提供数据冗余和/或性能提升。它的核心目的是提高数据的可靠性、可用性和访问速度。磁盘阵列可以由专用硬件或软件实现。 PVE部署磁盘阵列并加入虚拟机 …

FlinkSql使用中rank/dense_rank函数报错空指针

问题描述 在flink1.16(甚至以前的版本)中&#xff0c;使用rank()或者dense_rank()进行排序时&#xff0c;某些场景会导致报错空指针NPE(NullPointerError) 报错内容如下 该报错没有行号/错误位置&#xff0c;无法排查 现状 目前已经确认为bug&#xff0c;根据github上的PR日…

Ubuntu介绍、与centos的区别、基于VMware安装Ubuntu Server 22.04、配置远程连接、安装jdk+Tomcat

目录 ?编辑 一、Ubuntu22.04介绍 二、Ubuntu与Centos的区别 三、基于VMware安装Ubuntu Server 22.04 下载 VMware安装 1.创建新的虚拟机 2.选择类型配置 3.虚拟机硬件兼容性 4.安装客户机操作系统 5.选择客户机操作系统 6.命名虚拟机 7.处理器配置 8.虚拟机内存…

一个基于Python+Appium的手机自动化项目~~

本项目通过PythonAppium实现了抖音手机店铺的自动化询价&#xff0c;可以直接输出excel&#xff0c;并带有详细的LOG输出。 1.excel输出效果: 2. LOG效果: 具体文件内容见GitCode&#xff1a; 项目首页 - douyingoods:一个基于Pythonappium的手机自动化项目&#xff0c;实现了…

ubuntu 更新24LTS中断导致“系统出错且无法恢复,请联系系统管理员”

22LTS to 24LTS 更新过程中手jian把更新程序controlC导致的。 解决 目前企图完成更新来恢复&#xff0c;重启后有软件包冲突&#xff0c;sudo apt upgrade报冲突。无法进行。 将原来source.list重新 sudo dpkg --configure -a sudo apt install -f 这些都不管用。还是显示gno…

(2025,DeepSeek-R1-Zero,DeepSeek-R1,两阶段强化学习,两阶段监督微调,蒸馏,冷启动数据)通过强化学习激励 LLM 的推理能力

DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning 目录 0. 摘要 1. 简介 1.1 贡献 1.2 评测结果总结 2. 方法 2.1 概述 2.2 DeepSeek-R1-Zero&#xff1a;基础模型上的强化学习 2.2.1. 强化学习算法 2.2.2. 奖励建模 2.2.3. 训练…

k8s支持自定义field-selector spec.hostNetwork过滤

好久没写博客啦&#xff0c;年前写一个博客就算混过去啦&#x1f602; 写一个小功能&#xff0c;对于 Pod&#xff0c;在没有 label 的情况下&#xff0c;支持 --field-selector spec.hostNetwork 查询 Pod 是否为 hostNetwork 类型&#xff0c;只为了熟悉 APIServer 是如何构…

图漾相机搭配VisionPro使用简易教程

1.下载并安装VisionPro软件 请自行下载VisonPro软件。 VisionPro 9.0/9.5/9.6版本经测试&#xff0c;可正常打开图漾相机&#xff0c;建议使用图漾测试过的版本。 2.下载PercipioCameraForVisionPro软件包 使用浏览器下载&#xff1a;https://gitee.com/percipioxyz/camport3…

【MFC】C++所有控件随窗口大小全自动等比例缩放源码(控件内字体、列宽等未调整) 20250124

MFC界面全自动等比例缩放 1.在初始化里 枚举每个控件记录所有控件rect 2.在OnSize里&#xff0c;根据当前窗口和之前保存的窗口的宽高求比例x、y 3.枚举每个控件&#xff0c;根据比例x、y调整控件上下左右,并移动到新rect struct ControlInfo {CWnd* pControl;CRect original…