机器学习算法(二)---支持向量机SVM

文章介绍了监督学习中的支持向量机,包括线性分类器在二分类问题中的应用,以及如何通过核函数处理非线性问题。还探讨了线性回归器的支持向量机实例,展示了不同核函数对回归性能的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


常见的机器学习算法:
机器学习算法(一)—决策树
机器学习算法(二)—支持向量机SVM
机器学习算法(三)—K近邻
机器学习算法(四)—集成算法
基于XGBoost的集成学习算法
基于LightGBM的集成学习算法
机器学习算法(五)—聚类
机器学习算法(六)—逻辑回归
机器学习算法(七)—Apriori 关联分析
机器学习算法(八)—朴素贝叶斯
九种降维方法汇总

一、支持向量机

1.1 模型介绍

  支持向量机是一种二分类模型,它的目的就是构造一个“超平面”,并利用“超平面”将不同类别的样本做划分。同时使得样本集中的点到这个分类超平面的最小距离(即分类间隔)最大化。即搜索所有可能的线性分类器中最佳的那个,最终转化为一个凸二次规划问题求解。
  在样本空间中,划分超平面可通过如下线性方程来描述:
在这里插入图片描述
其中w=(w1,w2,…wn)为法向量,决定了超平面的方向,b为位移项,决定了超平面与原点之间的距离。划分超平面可被法向量w和位移b确定,可记为 (w,b) ,样本空间中任意点 x 到超平面(w,b)的距离可写为:
在这里插入图片描述
假设超平面 (w,b) 能将训练样本正确分类,即对于(Xi,Yi)∈D,有:
在这里插入图片描述
那么两个异类支持向量到超平面的距离之和为:
在这里插入图片描述
在这里插入图片描述
找到具有“最大间隔”的划分超平面,也就是要找到参数W和b,使得γ最大,即:
在这里插入图片描述
为了最大化间隔,等价于最小化w的平方,于是,最大化的等式可重写为:
在这里插入图片描述
这就是支持向量机的基本型。使用拉格朗日乘子法可得到其“对偶问题”,拉格朗日函数可写成:
在这里插入图片描述
解出a后,求出w和b即可得到模型。

1.2 损失函数

  SVM的损失函数就是合页损失函数加上正则化项:
在这里插入图片描述

1.3 模型参数

LinearSVC(
    penalty='l2',#字符串。可取值为'l1'和'l2'分别对应1范数和2范数
    loss='squared_hinge',#表示损失函数。可取值为'hinge':合页损失函数;'squared_hinge':合页损失函数的平方。
    dual=True,#布尔值。如果为true,则求解对偶问题。如果为false,解决原始问题。
    tol=0.0001,#SVM停止训练的误差精度
    C=1.0, #错误项的惩罚系数。c越大,即对分错样本的惩罚程度越大,减小c的话,允许训练样本中有一些误分类错误样本,泛化能力强。
    multi_class='ovr',#字符串,指定多分类问题的策略,'ovr': 采用one-vs-rest分类策略;'crammer_singer': 多类联合分类,很少用。
    fit_intercept=True,#布尔值。如果为true,则计算截距,即决策函数中的常数项;否则忽略截距
    intercept_scaling=1,#如果提供了,则实例X变成向量[X,intercept_scaling]。此时相当于添加了一个人工特征,该特征对所有实例都是常数值
    class_weight=None,#给每个类别分别设置不同的惩罚参数c,如果没有给,所有类别都是默认值。
    verbose=0,#是否启用详细输出。一般情况下设置为False。
    random_state=None,#伪随机数发生器的种子,在混洗数据时用于概率估计
    max_iter=1000,#最大迭代次数,如果为-1表示不受限制。
    )

1.4 实践案例

  本案例通过scikit-learn 内部集成的手写体数字图片数据集进行讲解分析。

from sklearn.datasets import load_digits  #加载手写体数字加载器
from sklearn.model_selection import train_test_split #用于分割数据集
from sklearn.preprocessing import StandardScaler     # 标准化
from sklearn.svm import LinearSVC  #线性分类支持向量机
digits=load_digits()
digits.data.shape
#输出:(1797, 64)

  该手写体数字的数码图像数据共有1797条,并且每幅图片是由8x8=64的像素矩阵表示。

x_train,x_test,y_train,y_test = train_test_split(digits.data,digits.target,test_size=0.3,random_state=33)
ss=StandardScaler() #数据标准化
X_train=ss.fit_transform(x_train)
X_test=ss.transform(x_test)
#初始化
lsvc=LinearSVC()
lsvc.fit(X_train,y_train)
lsvc_y_predict=lsvc.predict(X_test)
print('Accuracy of svc Classifier:',lsvc.score(X_test,y_test))
print(classification_report(y_test,lsvc_y_predict))

在这里插入图片描述
  支持向量机(分类)模型的确能够提供比较高的手写数字识别能力,平均各项指标都在95%上下。

二、非线性支持向量机

2.1 核函数

  非线性问题:SVM的处理方法是选择一个核函数,通过将数据映射到高维空间,来解决在原始空间中线性不可分的问题。如果原始空间是有限维,即属性数有限,那么一定存在一个高维特征空间使样本可分。
在这里插入图片描述
对偶理念和线性的思想一样。
常见的核函数:一般高斯核函数用的较多。
在这里插入图片描述

2.1.1 多项式核函数

#多项式核函数
from sklearn.svm import SVC
poly_kernel_svm_clf=Pipeline([("scaler",StandardScaler()),("svm_clf",SVC(kernel="poly",degree=3,coef0=1,C=5))])
poly_kernel_svm_clf.fit(X,y)

poly100_kernel_svm_clf=Pipeline([("scaler",StandardScaler()),("svm_clf",SVC(kernel="poly",degree=10,coef0=100,C=5))])
poly100_kernel_svm_clf.fit(X,y)

plt.figure(figsize=(11,4))
plt.subplot(121)
plot_predictions(poly_kernel_svm_clf)
plot_dataset(X,y)
plt.title(r"$d=3, r=1, C=5$",fontsize=18)
plt.subplot(122)
plot_predictions(poly100_kernel_svm_clf)
plot_dataset(X,y)
plt.title(r"$d=10, r=100, C=5$",fontsize=18)
plt.show()

在这里插入图片描述

2.1.2 高斯核函数

利用相似度来变换特征。

#高斯核函数
from sklearn.svm import SVC
gamma1,gamma2=0.1,5
C1,C2=0.001,1000
hyperparams=[(gamma1,C1),(gamma1,C2),(gamma2,C1),(gamma2,C2)]
svm_clfs=[]
for gamma,C in hyperparams:
    rbf_svm_clf=Pipeline([
        ("scaler",StandardScaler()),
        ("svm_clf",SVC(kernel="rbf",gamma=gamma,C=C))
    ])
    rbf_svm_clf.fit(X,y)
    svm_clfs.append(rbf_svm_clf)
plt.figure(figsize=(11,7))
for i,svm_clf in enumerate(svm_clfs):
    plt.subplot(221+i)
    plot_predictions(svm_clf)
    plot_dataset(X,y)
    gamma,C=hyperparams[i]
    plt.title(r"$\gamma = {}, C = {}$".format(gamma,C),fontsize=16)
plt.show()  

在这里插入图片描述

三、软间隔

  前面都是假定训练样本在样本空间或特征空间中是线性可分的,即存在一个超平面能将不同类的样本完全划分开,然而,现实中很难找到合适的核函数使得训练样本在特征空间中线性可分,缓解该问题的办法是允许支持向量机在一些样本上出错,为此,引入软间隔概念。

3.1 决策边界可视化

import numpy as np
import pandas as pd
import os
from sklearn import datasets
from sklearn.svm import SVC
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12

iris = datasets.load_iris()
X = iris.data[:, (2, 3)]
y = iris.target
setosa_or_versicolor = (y == 0) | (y == 1)
X = X[setosa_or_versicolor]
y = y[setosa_or_versicolor]
svm_clf = SVC(kernel='linear', C=float('inf'))
svm_clf.fit(X, y)

x0 = np.linspace(0, 5.5, 200)  # 保持为数组
pred_1 = 5 * x0 - 20
pred_2 = x0 - 1.8
pred_3 = 0.1 * x0 + 0.5

def plot_svc_decision_boundary(svm_clf, xmin, xmax, sv=True):
    w = svm_clf.coef_[0]  # 权重值
    b = svm_clf.intercept_[0]  # 偏置值
    x_vals = np.linspace(xmin, xmax, 200)  # 避免与全局变量 x0 冲突
    decision_boundary = -(w[0] * x_vals + b) / w[1]
    margin = 1 / w[1]
    gutter_up = decision_boundary + margin
    gutter_down = decision_boundary - margin
    if sv:
        sv = svm_clf.support_vectors_
        plt.scatter(sv[:, 0], sv[:, 1], s=180, facecolors='none', edgecolors='k')
    plt.plot(x_vals, decision_boundary, "k-", linewidth=2, label=u"decision boundary")
    plt.plot(x_vals, gutter_up, "k--", linewidth=2)
    plt.plot(x_vals, gutter_down, "k--", linewidth=2)

plt.figure(figsize=(12, 3))
plt.subplot(121)
plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], 'bs')
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], 'yo')
plt.plot(x0, pred_1, 'g--', linewidth=2)
plt.plot(x0, pred_2, 'y--', linewidth=2)
plt.plot(x0, pred_3, 'r--', linewidth=2)
plt.xlim(0, 5.5)
plt.ylim(0, 2)

plt.subplot(122)
plot_svc_decision_boundary(svm_clf, 0, 5.5)
plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], 'bs')
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], 'yo')
plt.xlim(0, 5.5)
plt.ylim(0, 2)
plt.show()

在这里插入图片描述

3.2 软间隔

使用超参数C控制软间隔程度

  • 使用较高的C值,分类器会减少误分类,但最终会有较小间隔。
  • 使用较低的C值,间隔要大得多,但很多实例最终会出现在间隔之内。
import numpy as np
from sklearn import datasets
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
import matplotlib.pyplot as plt

# 加载数据
iris = datasets.load_iris()
X = iris.data[:, (2, 3)]  # 花瓣长度和花瓣宽度
y = (iris.target == 2).astype(np.float64)  # 是否是 Iris-Virginica

# 创建 Pipeline
pipe_svc = Pipeline([
    ('sc', StandardScaler()),
    ('linear_svc', LinearSVC(C=1, loss='hinge'))
])
pipe_svc.fit(X, y)

# 预测
print(pipe_svc.predict([[5.5, 1.7]]))

# 对比不同的 C 值
scaler = StandardScaler()
svm_clf1 = LinearSVC(C=1, random_state=42, loss='hinge')
svm_clf2 = LinearSVC(C=100, random_state=42, loss='hinge')

scaled_svm_clf1 = Pipeline([
    ('scaler', scaler),
    ('linear_svc', svm_clf1)
])
scaled_svm_clf2 = Pipeline([
    ('scaler', scaler),
    ('linear_svc', svm_clf2)
])

scaled_svm_clf1.fit(X, y)
scaled_svm_clf2.fit(X, y)

# 获取模型的权重和偏置
b1 = svm_clf1.decision_function([-scaler.mean_ / scaler.scale_])
b2 = svm_clf2.decision_function([-scaler.mean_ / scaler.scale_])
w1 = svm_clf1.coef_[0] / scaler.scale_
w2 = svm_clf2.coef_[0] / scaler.scale_

svm_clf1.intercept_ = np.array([b1])
svm_clf2.intercept_ = np.array([b2])
svm_clf1.coef_ = np.array([w1])
svm_clf2.coef_ = np.array([w2])

# 绘制决策边界
def plot_svc_decision_boundary(svm_clf, xmin, xmax, sv=True):
    w = svm_clf.coef_[0]  # 权重值
    b = svm_clf.intercept_[0]  # 偏置值
    x_vals = np.linspace(xmin, xmax, 200)  # 避免与全局变量 x0 冲突
    decision_boundary = -(w[0] * x_vals + b) / w[1]
    margin = 1 / w[1]
    gutter_up = decision_boundary + margin
    gutter_down = decision_boundary - margin
    if sv:
        sv = svm_clf.support_vectors_
        plt.scatter(sv[:, 0], sv[:, 1], s=180, facecolors='none', edgecolors='k')
    plt.plot(x_vals, decision_boundary, "k-", linewidth=2, label=u"decision boundary")
    plt.plot(x_vals, gutter_up, "k--", linewidth=2)
    plt.plot(x_vals, gutter_down, "k--", linewidth=2)

plt.figure(figsize=(14, 4))

# 绘制 C=1 的决策边界
plt.subplot(121)
plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], 'bs', label=u'Iris-Virginica')
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], 'yo', label=u'Iris-Versicolor')
plot_svc_decision_boundary(scaled_svm_clf1.named_steps['linear_svc'], 4, 6, sv=False)  # 修正这里
plt.xlabel(u"Petal length", fontsize=14)
plt.ylabel(u"Petal width", fontsize=14)
plt.legend(loc='upper left', fontsize=14)
plt.title(u"$C=1$", fontsize=16)
plt.xlim(4, 6)
plt.ylim(0.8, 2.8)

# 绘制 C=100 的决策边界
plt.subplot(122)
plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], 'bs', label=u'Iris-Virginica')
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], 'yo', label=u'Iris-Versicolor')
plot_svc_decision_boundary(scaled_svm_clf2.named_steps['linear_svc'], 4, 6, sv=False)  # 修正这里
plt.xlabel(u"Petal length", fontsize=14)
plt.ylabel(u"Petal width", fontsize=14)
plt.legend(loc='upper left', fontsize=14)
plt.title(u"$C=100$", fontsize=16)
plt.xlim(4, 6)
plt.ylim(0.8, 2.8)

plt.show()

在这里插入图片描述

四、线性回归器-支持向量机

  支持向量机回归也同样是从训练数据中选取一部分更加有效的支持向量,只是这少部分的训练样本所提供的并不是类别目标,而是更加具体的预测数值。

from sklearn.svm import SVR
import pandas as pd
from sklearn.metrics import r2_score,mean_absolute_error,mean_squared_error
boston = pd.read_excel('boston_house_price.xlsx')
#使用线性核函数配置的支持向量机进行回归训练,并对测试样本进行预测
x=np.array(boston.iloc[:,:-1])
y=np.array(boston.iloc[:,-1])
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.25,random_state=33)

ss_x=StandardScaler()
X_train=ss_x.fit_transform(x_train) #x_train:(379, 13) X_train:(379, 13)
X_test=ss_x.transform(x_test)   #x_test:(127, 13)  X_test:(127, 13)
##说明一下:fit_transform与transform都要求操作2D数据,而此时的y_train与y_test都是1D的,因此需要调用reshape(-1,1),例如:[1,2,3]变成[[1],[2],[3]]
ss_y=StandardScaler()
Y_train=ss_y.fit_transform(y_train.reshape(-1,1))# y_train:(127,) Y_train:(127, 1)
Y_test=ss_y.transform(y_test.reshape(-1,1))   #y_test:(379,) Y_test:(379, 1)

#使用线性核函数配置的支持向量机进行回归训练,并且对测试样本进行预测
linear_svr = SVR(kernel='linear')
linear_svr.fit(X_train,Y_train)
linear_svr_y_predict =linear_svr.predict(X_test)

#使用多项式核函数配置的支持向量机进行回归训练,并且对测试样本进行预测
poly_svr = SVR(kernel='poly')
poly_svr.fit(X_train,Y_train)
poly_svr_y_predict =poly_svr.predict(X_test)

#使用径向基核函数配置的支持向量机进行回归训练,并且对测试样本进行预测
rbf_svr = SVR(kernel='rbf')
rbf_svr.fit(X_train,Y_train)
rbf_svr_y_predict =rbf_svr.predict(X_test)

print('The r2 value of linear SVR is :',linear_svr.score(X_test,Y_test))
print('The mean squared error of linear SVR is :',mean_squared_error(y_test.reshape(-1,1),ss_y.inverse_transform(linear_svr_y_predict.reshape(-1,1)))) #(127, 1),#ss_y.inverse_transform(linear_svr_y_predict.reshape(-1,1)))(127, 1)
print('The mean absoluate error of linear SVR is :',mean_absolute_error(y_test.reshape(-1,1),ss_y.inverse_transform(linear_svr_y_predict.reshape(-1,1))))

在这里插入图片描述

print('The r2 value of poly SVR is :',poly_svr.score(X_test,Y_test))
print('The mean squared error of poly SVR is :',mean_squared_error(y_test.reshape(-1,1),ss_y.inverse_transform(poly_svr_y_predict.reshape(-1,1)))) #(127, 1),#ss_y.inverse_transform(linear_svr_y_predict.reshape(-1,1)))(127, 1)
print('The mean absoluate error of poly SVR is :',mean_absolute_error(y_test.reshape(-1,1),ss_y.inverse_transform(poly_svr_y_predict.reshape(-1,1))))

在这里插入图片描述

print('The r2 value of rbf SVR is :',rbf_svr.score(X_test,Y_test))
print('The mean squared error of rbf SVR is :',mean_squared_error(y_test.reshape(-1,1),ss_y.inverse_transform(rbf_svr_y_predict.reshape(-1,1)))) #(127, 1),#ss_y.inverse_transform(linear_svr_y_predict.reshape(-1,1)))(127, 1)
print('The mean absoluate error of rbf SVR is :',mean_absolute_error(y_test.reshape(-1,1),ss_y.inverse_transform(rbf_svr_y_predict.reshape(-1,1))))

在这里插入图片描述
  综上三种不同核函数配置下的支持向量机回归模型在测试集上的回归性能评估发现,不同配置下的模型在相同测试集上,存在非常大的差异,并且使用径向基核函数对特征进行非线性映射后,支持向量机展现了最佳的回归性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值