一.算法概念
1.1定义
支持向量机(support vector machines,SVM)是一种二分类模型,它的目的是寻找一个超平面来对样本进行分割,分割的原则是间隔最大化。SVM的目标就是要找到这个超平面。
1.2间隔与超平面
能在实验中将数据集分隔开的直线一般称为分隔超平面。而点到分隔面的距离则被我们称之为间隔。
而在所要求的样本空间中,超平面的函数表达形式一般写作:
其中b的含义与Logistic回归中的截距w0类似。
而任意一点A(w,b)到超平面的距离(通过高中所学的点到直线的距离公式)可写作:
根据上述公式可以得出间隔:
如下图
二.算法流程
2.1SVM的一般流程
(1)收集数据:可以使用任何方法
(2)准备数据:需要数值型数据
(3)分析数据:有助于可视化分割超平面
(4)训练算法:SVM的大部分时间都源自训练,该过程主要实现两个参数的调优
(5)测试算法:用简单的计算过程实现
(6)使用算法:解决分类问题
2.2算法初步实现
2.2.1实现SVM分类器
定义一个名为LinearSVM的类,用于实现线性支持向量机算法。其中包含类的初始化方法、fit方法和predict方法。
根据公式设置学习率、正则化参数和迭代次数等参数。
class LinearSVM:
def __init__(self,learning_rate=0.0001,lambda_param=0.1,n_iters=1000):
self.learning_rate=learning_rate#学习率
self.lambda_param=lambda_param#正则化参数
self.n_iters=n_iters#迭代次数
self.w=None
self.b=None
def fit(self,X,y):#fit方法用于模型训练
n_samples,n_features=X.shape
y_ =np.where(y<=0,-1,1)
#初始化权重和偏置为0
self.w=np.zeros(n_features)
self.b=0
for _ in range(self.n_iters):
for idx,x_i in enumerate(X):
condition = y_[idx]*(np.dot(x_i,self.w)-self.b)>=1 #遍历每个样本,检查分类条件
if condition:
self.w-=self.learning_rate*(2*self.lambda_param*self.w)#如果样本被正确分类且在正确的间隔外,仅通过正则项更行权重(防止过拟合)
else:
self.w-=self.learning_rate*(2*self.lambda_param*self.w-np.dot(x_i,y_[idx]))#样本被错误分类或者在间隔内,则权重更新包括误差项,同时更新偏置,使样本在未来被正确分类
self.b-=self.learning_rate*y_[idx]
def predict(self,X):
Linear_output=np.dot(X,self.w)-self.b
return np.sign(Linear_output)
2.2.2实现结果可视化
定义一个名为plot_hyperplane的函数,用于绘制数据集和分类超平面。首先绘制散点图,然后获取坐标轴的范围,生成网格点,计算网格点的Z值,最后绘制等高线。
#结果可视化
def plot_hyperplane(X,y,w,b):
plt.scatter(X[:,0],X[:,1],marker='o',c=y,s=100,edgecolors='k',cmap='winter')
ax=plt.gca()
xlim=ax.get_xlim()
ylim=ax.get_ylim()
xx=np.linspace(xlim[0],xlim[1],30)
yy=np.linspace(ylim[0],ylim[1],30)
YY,XX=np.meshgrid(yy,xx)
xy=np.vstack([XX.ravel(),YY.ravel()]).T
Z=(np.dot(xy,w)-b).reshape(XX.shape)
ax.contour(XX,YY,Z,colors='k',levels=[-1,0,1],alpha=0.5,linestyles=['--','-','--'])
plt.show()
2.2.3准备一组数据进行实验
使用sklearn.datasets中的make_blobs函数生成一个包含100个样本、2个中心点的数据集。将标签y调整为-1和1,然后创建一个LinearSVM实例,调用fit方法进行训练。再调用plot_hyperplane函数,可视化训练结果。
#数据准备和模型训练
X,y=datasets.make_blobs(n_samples=100,centers=2,random_state=6)
y=np.where(y==0,-1,1)#调整标签为-1和1
svm0=LinearSVM()
svm0.fit(X,y)
plot_hyperplane(X,y,svm0.w,svm0.b) # type: ignore
2.2.4调整C后再次实验
参数C控制了错误分类训练示例的惩罚。参数C越大,则告诉SVM要对所有的例子进行正确的分类。
显然我们发现当C比较小时,模型对错误分类的惩罚较小,比较松弛,样本点之间的间隔就比较大,可能产生欠拟合的情况。
当C比较大时,模型对错误分类的惩罚较大,两组数据之间的间隔就小,容易产生过拟合的情况
C值越大,越不容易放弃那些离群点;C值越小,越不重视那些离群点。
#调整C参数看不同的效果
class LinearSVM1:
def __init__(self,C=1.0,learning_rate=0.0001,n_iters=1000):
self.C=C
self.learning_rate=learning_rate
self.n_iters=n_iters
self.w=None
self.b=None
def fit(self,X,y):
n_samples,n_features=X.shape
y_ =np.where(y<=0,-1,1)
#初始化权重和偏置为0
self.w=np.zeros(n_features)
self.b=0
for _ in range(self.n_iters):
for idx,x_i in enumerate(X):
condition = y_[idx]*(np.dot(x_i,self.w)-self.b)>=1 #遍历每个样本,检查分类条件
if condition:
self.w-=self.learning_rate*(2*self.w)#如果样本被正确分类且在正确的间隔外,仅通过正则项更行权重(防止过拟合)
else:
self.w-=self.learning_rate*((2*self.w)-self.C*np.dot(x_i,y_[idx]))#样本被错误分类或者在间隔内,则权重更新包括误差项,同时更新偏置,使样本在未来被正确分类
self.b-=self.learning_rate*self.C*y_[idx]
def predict(self,X):
Linear_output=np.dot(X,self.w)-self.b
return np.sign(Linear_output)
#数据准备和模型训练
X,y=datasets.make_blobs(n_samples=100,centers=2,random_state=6)
y=np.where(y==0,-1,1)#调整标签为-1和1
svm1=LinearSVM1(C=200)
svm1.fit(X,y)
plot_hyperplane(X,y,svm1.w,svm1.b) # type: ignore
2.2.5两次实验结果
2.2.6整体代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
class LinearSVM:
def __init__(self,learning_rate=0.0001,lambda_param=0.1,n_iters=1000):
self.learning_rate=learning_rate#学习率
self.lambda_param=lambda_param#正则化参数
self.n_iters=n_iters#迭代次数
self.w=None
self.b=None
def fit(self,X,y):#fit方法用于模型训练
n_samples,n_features=X.shape
y_ =np.where(y<=0,-1,1)
#初始化权重和偏置为0
self.w=np.zeros(n_features)
self.b=0
for _ in range(self.n_iters):
for idx,x_i in enumerate(X):
condition = y_[idx]*(np.dot(x_i,self.w)-self.b)>=1 #遍历每个样本,检查分类条件
if condition:
self.w-=self.learning_rate*(2*self.lambda_param*self.w)#如果样本被正确分类且在正确的间隔外,仅通过正则项更行权重(防止过拟合)
else:
self.w-=self.learning_rate*(2*self.lambda_param*self.w-np.dot(x_i,y_[idx]))#样本被错误分类或者在间隔内,则权重更新包括误差项,同时更新偏置,使样本在未来被正确分类
self.b-=self.learning_rate*y_[idx]
def predict(self,X):
Linear_output=np.dot(X,self.w)-self.b
return np.sign(Linear_output)
#结果可视化
def plot_hyperplane(X,y,w,b):
plt.scatter(X[:,0],X[:,1],marker='o',c=y,s=100,edgecolors='k',cmap='winter')
ax=plt.gca()
xlim=ax.get_xlim()
ylim=ax.get_ylim()
xx=np.linspace(xlim[0],xlim[1],30)
yy=np.linspace(ylim[0],ylim[1],30)
YY,XX=np.meshgrid(yy,xx)
xy=np.vstack([XX.ravel(),YY.ravel()]).T
Z=(np.dot(xy,w)-b).reshape(XX.shape)
ax.contour(XX,YY,Z,colors='k',levels=[-1,0,1],alpha=0.5,linestyles=['--','-','--'])
plt.show()
#数据准备和模型训练
X,y=datasets.make_blobs(n_samples=100,centers=2,random_state=6)
y=np.where(y==0,-1,1)#调整标签为-1和1
svm0=LinearSVM()
svm0.fit(X,y)
plot_hyperplane(X,y,svm0.w,svm0.b) # type: ignore
#调整C参数看不同的效果
class LinearSVM1:
def __init__(self,C=1.0,learning_rate=0.0001,n_iters=1000):
self.C=C
self.learning_rate=learning_rate
self.n_iters=n_iters
self.w=None
self.b=None
def fit(self,X,y):
n_samples,n_features=X.shape
y_ =np.where(y<=0,-1,1)
#初始化权重和偏置为0
self.w=np.zeros(n_features)
self.b=0
for _ in range(self.n_iters):
for idx,x_i in enumerate(X):
condition = y_[idx]*(np.dot(x_i,self.w)-self.b)>=1 #遍历每个样本,检查分类条件
if condition:
self.w-=self.learning_rate*(2*self.w)#如果样本被正确分类且在正确的间隔外,仅通过正则项更行权重(防止过拟合)
else:
self.w-=self.learning_rate*((2*self.w)-self.C*np.dot(x_i,y_[idx]))#样本被错误分类或者在间隔内,则权重更新包括误差项,同时更新偏置,使样本在未来被正确分类
self.b-=self.learning_rate*self.C*y_[idx]
def predict(self,X):
Linear_output=np.dot(X,self.w)-self.b
return np.sign(Linear_output)
#数据准备和模型训练
X,y=datasets.make_blobs(n_samples=100,centers=2,random_state=6)
y=np.where(y==0,-1,1)#调整标签为-1和1
svm1=LinearSVM1(C=200)
svm1.fit(X,y)
plot_hyperplane(X,y,svm1.w,svm1.b) # type: ignore
三.核函数
3.1概念
支持向量机算法分类和回归方法的中都支持线性性和非线性类型的数据类型。非线性类型通常是二维平面不可分,为了使数据可分,需要通过一个函数将原始数据映射到高维空间,从而使得数据在高维空间很容易可分,需要通过一个函数将原始数据映射到高维空间,从而使得数据在高维空间很容易区分,这样就达到数据分类或回归的目的,而实现这一目标的函数称为核函数。
工作原理:当低维空间内线性不可分时,可以通过高位空间实现线性可分。但如果在高维空间内直接进行分类或回归时,则存在确定非线性映射函数的形式和参数问题,而最大的障碍就是高维空间的运算困难且结果不理想。通过核函数的方法,可以将高维空间内的点积运算,巧妙转化为低维输入空间内核函数的运算,从而有效解决这一问题。
3.2常见的核函数
四.实验小结
在分类问题中,SVM是一种很优秀的机器学习算法。SVM可以有效的分离高维度的数据,更节省内存空间,因为只需要用向量来创建最佳超平面,是针对于可分离数据集的最佳方法。但是当数据量级较大的时候,分类效果不好,针对于不可分类的数据集,效果有些不太好。这次实验让我对支持向量机有了一定的了解和认识,能运用其解决实际问题,但还不能熟练使用,要继续加强对机器学习相关知识的学习。总的来说是一次收获满满的实验。