当前位置: 首页 > news >正文

基于sklearn的机器学习 — 支持向量机(SVM)

支持向量机(SVM:support vector machine)另一种功能强大、应用广泛的学习算法,可应用于分类、回归、密度估计、聚类等问题。SVM可以看作是感知器(可被视为一种最简单形式的前馈神经网络,是一种二元线性分类器)的扩展,与逻辑回归相比,支持向量机在学习复杂的非线性方程时提供了一种更为清晰,更加强大的方式。

SVM是一种监督式的学习方法,用统计风险最小化的原则来估计一个分类的超平面(hyperplane) ,其基础的概念非常简单,就是找到一个决策边界(decision boundary) ,让两类之间的边界(margins) 最大化,使其可以完美地分隔开来。

超平面(hyperplane) 是n维空间中的n - 1个子空间。例如,想要划分一个二维空间,需要使用一维超平面(即一条线),划分三维空间,需要使用二维超平面(即一张面),超平面只是将这一概念推广到 n 维空间。

不同维度下的超平面

支持向量(support vectors) 指的是最接近超平面或超平面上的数据点,它们影响超平面的位置和方向。

边界(margin) 的定义是:分离超平面(决策边界)与最接近该超平面的训练实例(即支持向量)之间的距离。

支持向量与边界

1. 支持向量机的类型

支持向量机有两种类型:

  1. 线性支持向量机
  2. 非线性支持向量机

线性与非线性可分问题

1.1 线性支持向量机

线性SVM适用于训练数据近似线性可分的情况,在这种情况下,存在一个超平面可以将不同类的样本完全划分开。

使用支持向量分类器 (SVC:support vector classifier) 查找使类之间的边距最大化的超平面,scikit-learn 的 LinearSVC实现了一个简单的 SVC。

下面基于鸢尾花数据集,在二维空间上对两组数据进行分类,然后绘制超平面:

# Load libraries  
from sklearn.svm import LinearSVC 
from sklearn import datasets 
from sklearn.preprocessing import StandardScaler 
import numpy as np  # Load data with only two classes and two features 
iris = datasets.load_iris() 
features = iris.data[:100,:2] 
target = iris.target[:100]  # Standardize features  
scaler = StandardScaler() 
features_standardized = scaler.fit_transform(features)  # Create support vector classifier 
svc = LinearSVC(C=1.0)  # Train model  
model = svc.fit(features_standardized, target)# Plot data points and color using their class  
color = ["red" if c == 0 else "black" for c in target] 
plt.scatter(features_standardized[:,0], features_standardized[:,1], c=color)# Create the hyperplane 
w = svc.coef_[0] 
a = -w[0] / w[1] 
xx = np.linspace(-2.5, 2.5) 
yy = a * xx - (svc.intercept_[0]) / w[1]# Plot the hyperplane 
plt.plot(xx, yy) 
plt.xlabel('Sepal length [standardized]')
plt.ylabel('Sepal width [standardized]')
plt.tight_layout()
plt.legend()
plt.show()

1.2 非线性支持向量机

对于线性不可分的问题,SVM可以借助核方法(Kernel methods)将样本从低维空间 (输入空间) 映射到高维空间 (特征空间) 来进行线性划分,从而解决非线性分类问题。

使用核方法对非线性数据进行分类的过程

上图展示了如何通过将数据投影到更高维度的空间来实现非线性可分数据的分类。

图中显示了一个二维平面上的数据集。红色圆点和蓝色方块代表两类数据,数据是非线性可分的,即没有一条直线可以将两类数据完美地分开。

通过使用映射函数( ϕ \phi ϕ)将原始的二维数据投影到三维空间,在这个新的高维空间中,原本在二维空间中非线性可分的数据,现在在三维空间中变得线性可分。

在三维空间中,我们可以学习一个线性分类器(比如一个超平面)来将两类数据分开。

通过逆映射函数( ϕ − 1 \phi^{-1} ϕ1),将三维空间中的决策边界投影回原始的二维空间,投影回二维空间后的决策边界不再是直线,而是曲线,这条曲线能很好地将两类数据分开。

通过核方法可以将非线性可分的数据映射到高维空间,在高维空间中应用线性分类器,然后将高维空间中的分类结果逆映射回原始空间,从而实现非线性分类。

下面通过一个简单的例子来理解,首先创建一个非线性可分的数据集:

# Load libraries  
from sklearn.svm import SVC 
from sklearn import datasets 
from sklearn.preprocessing import StandardScaler 
import numpy as np  # Set randomization seed 
np.random.seed(0)  # Generate two features  
features = np.random.randn(200, 2)  # Use an XOR gate to generate 
# linearly inseparable classes  
target_xor = np.logical_xor(features[:, 0] > 0, features[:, 1] > 0) 
target = np.where(target_xor, 0, 1)  # Create a support vector machine with a radial basis function kernel 
svc = SVC(kernel="rbf", random_state=0, gamma=1, C=1)  # Train the classifier  
model = svc.fit(features, target)

接着编写一个可以绘制二维空间的观测值和决策边界超平面的函数:

from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
def plot_decision_regions(X, y, classifier, test_idx=None,  resolution=0.02):  
# setup marker generator and color map  markers = ('o', 's', '^', 'v', '<') colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')cmap = ListedColormap(colors[:len(np.unique(y))])x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1  x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1  xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),  np.arange(x2_min, x2_max, resolution))  lab = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)  lab = lab.reshape(xx1.shape)  plt.contourf(xx1, xx2, lab, alpha=0.3, cmap=cmap)  plt.xlim(xx1.min(), xx1.max())  plt.ylim(xx2.min(), xx2.max())for idx, cl in enumerate(np.unique(y)):  plt.scatter(x=X[y == cl, 0],  y=X[y == cl, 1],  alpha=0.8,  c=colors[idx],  marker=markers[idx],  label=f'Class {cl}',  edgecolor='black')if test_idx:  # plot all examples  X_test, y_test = X[test_idx, :], y[test_idx]  plt.scatter(X_test[:, 0], X_test[:, 1], c='none', edgecolor='black', alpha=1.0,  linewidth=1, marker='o',  s=100, label='Test set')

上文创建的非线性数据集包含两个特征(即两个维度)和一个包含每个观测值类别的目标向量。

如果使用线性内核的支持向量机分类器进行分类:

# Create support vector classifier with a linear kernel 
svc_linear = SVC(kernel="linear", random_state=0, C=1)  # Train model  
svc_linear.fit(features, target)  # Plot observations and hyperplane  
plot_decision_regions(features, target, classifier=svc_linear) 
plt.legend()
plt.tight_layout()
plt.show()

可以看到,线性超平面的划分效果很差

现在将线性核函数换成径向基核函数,训练一个新模型:

# Create a support vector machine with a radial basis function kernel 
svc = SVC(kernel="rbf", random_state=0, gamma=1, C=1)# Train the classifier  
model = svc.fit(features, target)# Plot observations and hyperplane  
plot_decision_regions(features, target, classifier=svc) 
plt.legend()
plt.tight_layout()
plt.show()

划分结果为:

通过使用径向基核函数,可以创建一个更好的决策边界,这就是在支持向量机中使用核方法的目的。

在 scikit-learn中,我们可以通过kernel参数来选择要使用的核函数。

选择内核后,我们需要指定适当的内核选项,例如多项式内核(polynomial kernels)中的 d值,以及径向基函数内核中的γ值,还需要设置惩罚参数C

在训练模型时,大多数情况下我们应该将所有这些参数都视为超参数,并使用模型选择技术来确定它们的组合值,以产生性能最佳的模型。

2. 计算预测概率

许多监督学习算法都使用概率估计来预测类别。SVC 使用超平面来创建决策区域,并不能自然地输出观测值属于某个类别的概率估计值。不过,我们可以输出经过校准的类别概率。

在具有两个类别的 SVC 中,可以使用普拉特缩放(Platt scaling)法,即首先训练 SVC,然后训练一个单独的交叉验证逻辑回归,将 SVC 输出映射为概率:

P ( y = 1 ∣ x ) = 1 1 + e ( A × f ( x ) + B ) P(y=1\mid x)=\frac{1}{1+e^{(A\times f(x)+B)}} P(y=1x)=1+e(A×f(x)+B)1

式中:A 和 B 是参数向量, f ( x ) f(x) f(x)是第 i 个观测值距超平面的有符号距离。当我们有两个以上的类时,将使用普拉特缩放的扩展。

从更实际的角度来看,创建预测概率有两个主要问题:

  1. 由于我们要通过交叉验证来训练第二个模型,因此生成预测概率会大大增加训练模型所需的时间。

  2. 由于预测概率是通过交叉验证创建的,因此它们可能不总是与预测类别相匹配。也就是说,一个观测值可能被预测为类别 1,但预测为类别1的概率却小于 0.5。

在 scikit-learn 中,预测概率必须在训练模型时生成,我们可以将 SVC 的probability参数设置为 True,模型训练完成后,我们可以使用 predict_proba输出每个类别的估计概率。

# Load libraries  
from sklearn.svm import SVC 
from sklearn import datasets 
from sklearn.preprocessing import StandardScaler 
import numpy as np  # Load data  
iris = datasets.load_iris() 
features = iris.data 
target = iris.target  # Standardize features  
scaler = StandardScaler() 
features_standardized = scaler.fit_transform(features)  # Create support vector classifier object  
svc = SVC(kernel="linear", probability=True, random_state=0)  # Train classifier  
model = svc.fit(features_standardized, target)  # Create new observation  
new_observation = [[.1, .2, .3, .4]]  # View predicted probabilities  
model.predict_proba(new_observation)  

3. 识别支持向量

支持向量机之所以得名,是因为超平面是由相对较少的观测数据决定的,这些观测数据被称为支持向量。

直观地说,超平面就是由这些支持向量所"承载 ",因此,这些支持向量对我们的模型非常重要。

如果我们从数据中移除一个不属于支持向量的观测值,模型不会发生变化;但如果我们移除一个支持向量,超平面就不会有最大边界。

因此有时需要确定哪些观测值是决策超平面的支持向量。

在我们基于鸢尾花数据集训练出SVC后,scikit-learn提供了许多用于识别支持向量的选项,可以使用support_vectors_来输出模型中的支持向量:

# Load libraries  
from sklearn.svm import SVC 
from sklearn import datasets 
from sklearn.preprocessing import StandardScaler 
import numpy as np  # Load data with only two classes 
iris = datasets.load_iris() 
features = iris.data[:100,:] 
target = iris.target[:100]  # Standardize features  
scaler = StandardScaler() 
features_standardized = scaler.fit_transform(features)  # Create support vector classifier object 
svc = SVC(kernel="linear", random_state=0)  # Train classifier  
model = svc.fit(features_standardized, target)# View support vectors 
model.support_vectors_

结果有四个支持向量:

array([[-0.5810659 ,  0.42196824, -0.80497402, -0.50860702],[-1.52079513, -1.67737625, -1.08231219, -0.86427627],[-0.89430898, -1.4674418 ,  0.30437864,  0.38056609],[-0.5810659 , -1.25750735,  0.09637501,  0.55840072]])

另外,也可以使用support_查看支持向量的索引:

model.support_  

运行后可得到上述四个支持向量的索引:

array([23, 41, 57, 98])

最后,可以使用n_support_来查找属于每个分类的支持向量的数量:

model.n_support_ 

结果为:

array([2, 2])

4. 不平衡问题

不平衡问题指的是在对样本进行分类过程中,需要更加重视某些类或某些单个样本的情况。

在支持向量机中,C是一个超参数,决定了对错误分类观测值的惩罚,处理不平衡类别的一种方法是按类别对C进行加权:

C k = C × w j C_{k}=C\times w_{j} Ck=C×wj

其中,C是对错误分类的惩罚,wj是与类别j的频率成反比的权重,Ck 是类别k的C值。

一般的想法是增加对错误分类少数类别的惩罚,以防止它们被多数类别 “淹没”。

在 scikit-learn 中,当使用 SVC 时,我们可以通过设置class_weight="balanced"自动设置Ck的值,平衡参数自动对类进行权重,使得:

w j = n k n j w_j=\frac{n}{kn_j} wj=knjn

其中,wj是j类的权重,n是观测值的数量,nj是j类中观测值的数量,k是类的总数。

例如:

# Load libraries  
from sklearn.svm import SVC 
from sklearn import datasets 
from sklearn.preprocessing import StandardScaler 
import numpy as np# Load data with only two classes 
iris = datasets.load_iris() 
features = iris.data[:100,:] 
target = iris.target[:100]  # Make class highly imbalanced by removing first 40 observations 
features = features[40:,:] 
target = target[40:]  # Create target vector indicating if class 0, otherwise 1 
target = np.where((target == 0), 0, 1)  # Standardize features  
scaler = StandardScaler() 
features_standardized = scaler.fit_transform(features)  # Create support vector classifier  
svc = SVC(kernel="linear", class_weight="balanced", C=1.0, random_state=0)  # Train classifier  
model = svc.fit(features_standardized, target)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 使用C#(winform)调用STK并展示其3D/2D控件
  • 【前缀异或和】力扣2588. 统计美丽子数组数目
  • 【脚本说明撰写markdown】如何基于VScode 撰写使用说明文档,及格式转换.md、.html、.pdf格式
  • LVS--DR模式
  • 游戏盾是什么,如何保护网络游戏的安全
  • 大模型日报 2024-08-07
  • 用录制好的视频文件模拟PC电脑摄像头进行无人值守直播/抖音直播/视频号直播/快手直播
  • 将本地微服务发布到docker镜像二:
  • Linux下安装Go语言环境的详细指南
  • 给本地设备搭建一个云端语音助手
  • Rider中修改默认文件关联,自定义打开方式
  • opencascade TopoDS_Builder 源码学习
  • Apache Doris + Iceberg 快速搭建指南|Lakehouse 使用手册(三)
  • Openwrt常用说明
  • (四)activit5.23.0修复跟踪高亮显示BUG
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • CAP理论的例子讲解
  • egg(89)--egg之redis的发布和订阅
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • Java 23种设计模式 之单例模式 7种实现方式
  • java 多线程基础, 我觉得还是有必要看看的
  • Java超时控制的实现
  • Js基础知识(一) - 变量
  • MySQL的数据类型
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • Sass Day-01
  • 前端性能优化——回流与重绘
  • 翻译 | The Principles of OOD 面向对象设计原则
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • # 数论-逆元
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (黑马C++)L06 重载与继承
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (顺序)容器的好伴侣 --- 容器适配器
  • (图)IntelliTrace Tools 跟踪云端程序
  • (一)WLAN定义和基本架构转
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • .net core 6 集成和使用 mongodb
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • //解决validator验证插件多个name相同只验证第一的问题
  • @selector(..)警告提示
  • [ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决
  • [ 云计算 | AWS ] AI 编程助手新势力 Amazon CodeWhisperer:优势功能及实用技巧
  • [AI]ChatGPT4 与 ChatGPT3.5 区别有多大
  • [ai笔记4] 将AI工具场景化,应用于生活和工作
  • [C#]使用PaddleInference图片旋转四种角度检测
  • [C++]使用yolov10的onnx模型结合onnxruntime和bytetrack实现目标追踪
  • [LeetCode]Max Points on a Line
  • [pasecactf_2019]flask_ssti proc ssti config