SVM深入理解

一、支持向量机

  1. 支持向量机(Support Vector Machine,常简称为SVM)是一种监督式学习的方法,可广泛地应用于统计分类以及回归分析。
  2. 它是将向量映射到一个更高维的空间里,在这个空间里建立有一个最大间隔超平面。在分开数据的超平面的两边建有两个互相平行的超平面,分隔超平面使两个平行超平面的距离最大化。假定平行超平面间的距离或差距越大,分类器的总误差越小。

在这里插入图片描述

1. SVM

  1. 支持向量机的基本型
    在这里插入图片描述
  2. 软间隔的优化目标
    在这里插入图片描述
  3. SVM异常处理机制
    • 放松限制 在这里插入图片描述
    • 不放松机制 在这里插入图片描述
    • 必须放松限制 在这里插入图片描述

2. 核函数

对于线性不可分问题,线性可分支持向量机并不能有效解决。
在这里插入图片描述
非线性:

  • 首先使用一个非线性映射将数据变换到另一个特征空间
  • 在高维的特征空间中使用线性学习器分类

SVM对偶形式的求解
在这里插入图片描述
模型的最优解可通过训练样本的核函数展开,这一展开式称之为“支持向量机展式”

二、月亮数据集

1. 线性SVM

  1. 导入包
# 导入月亮数据集和svm方法
#这是线性svm
from sklearn import datasets #导入数据集
from sklearn.svm import LinearSVC #导入线性svm
from matplotlib.colors import ListedColormap
from sklearn.preprocessing import StandardScaler
  1. 获取响应的月亮数据集
    在这里插入图片描述
    • 月亮数据集是很圆滑的两个弧线,这里设置random_state,使数据没那么有规律
  2. 进行标准化并进行数据训练
scaler=StandardScaler()# 标准化
scaler.fit(data_x)#计算训练数据的均值和方差
data_x=scaler.transform(data_x) #再用scaler中的均值和方差来转换X,使X标准化
liner_svc=LinearSVC(C=1e9,max_iter=100000)#线性svm分类器,iter是迭达次数,c值决定的是容错,c越大,容错越小
liner_svc.fit(data_x,data_y)
  1. 绘制边界函数,进行后续可视化分类
# 边界绘制函数
def plot_decision_boundary(model,axis):
    x0,x1=np.meshgrid(
        np.linspace(axis[0],axis[1],int((axis[1]-axis[0])*100)).reshape(-1,1),
        np.linspace(axis[2],axis[3],int((axis[3]-axis[2])*100)).reshape(-1,1))
    # meshgrid函数是从坐标向量中返回坐标矩阵
    x_new=np.c_[x0.ravel(),x1.ravel()]
    y_predict=model.predict(x_new)#获取预测值
    zz=y_predict.reshape(x0.shape)
    custom_cmap=ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
    plt.contourf(x0,x1,zz,cmap=custom_cmap)
  1. 画图,输出参数已经截距权重
#画图并显示参数和截距
plot_decision_boundary(liner_svc,axis=[-3,3,-3,3])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1],color='red')
plt.scatter(data_x[data_y==1,0],data_x[data_y==1,1],color='blue')
plt.show()
print('参数权重')
print(liner_svc.coef_)
print('模型截距')
print(liner_svc.intercept_)

在这里插入图片描述
这种情况下线性svm效果并不好

2. 多项式核

  1. 导入所需的包
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
  1. 构建月亮数据集并可视化
X, y = datasets.make_moons() #使用生成的数据
#print(X.shape) # (100,2)
#print(y.shape) # (100,)
plt.scatter(X[y==0,0],X[y==0,1]) 
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()

在这里插入图片描述
3. 生成噪声点并可视化

X, y = datasets.make_moons(noise=0.15,random_state=777) #随机生成噪声点,random_state是随机种子,noise是方差
plt.scatter(X[y==0,0],X[y==0,1]) 
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()

在这里插入图片描述
4. 定义非线性SVM函数

def PolynomialSVC(degree,C=1.0):
    return Pipeline([
        ("poly",PolynomialFeatures(degree=degree)),#生成多项式
        ("std_scaler",StandardScaler()),#标准化
        ("linearSVC",LinearSVC(C=C))#最后生成svm
    ])
  1. 调用PolynomialSVC函数进行分类可视化
    • 调用非线性SVM分类,实例化SVC
poly_svc = PolynomialSVC(degree=5)
poly_svc.fit(X,y)
plot_decision_boundary(poly_svc,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(X[y==0,0],X[y==0,1]) 
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()

在这里插入图片描述
在这里插入图片描述
生成的边界不再是线性的直线了,因为月亮数据集提取的两个特征并不是线性的,所以决策边界自然不会是线性
6. 核处理

def PolynomialKernelSVC(degree,C=1.0):
    return Pipeline([
        ("std_scaler",StandardScaler()),
        ("kernelSVC",SVC(kernel="poly")) # poly代表多项式特征
    ])
poly_kernel_svc = PolynomialKernelSVC(degree=5)
poly_kernel_svc.fit(X,y)
plot_decision_boundary(poly_kernel_svc,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(X[y==0,0],X[y==0,1]) 
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()

在这里插入图片描述
此时仍为非线性,但是慢慢趋近于线性

3. 高斯核

  1. 导入相应的包
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
  1. 导入相应的月亮数据集
X,y = datasets.make_moons(noise=0.15,random_state=777)
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()

在这里插入图片描述
3. 定义RBF核的SVM函数

def RBFKernelSVC(gamma=1.0):
    return Pipeline([
        ('std_scaler',StandardScaler()),
        ('svc',SVC(kernel='rbf',gamma=gamma))
    ])
  1. 实例化并向γ传递参数
    • γ=200
      在这里插入图片描述
      γ 取值越大,就是高斯分布的钟形图越窄,这里相当于每个样本点都形成了钟形图。很明显这样是过拟合的
    • γ=2 -
    • γ=0.1 在这里插入图片描述
      欠拟合的。我们可以看出γ 值相当于在调整模型的复杂度
svc = RBFKernelSVC(gamma=200)
svc.fit(X,y)
plot_decision_boundary(svc,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(X[y==0,0],X[y==0,1]) 
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()

三、鸢尾花数据集

  1. 导入相关库
import numpy as np
from sklearn import datasets   #导入数据集
import matplotlib.pyplot as plt  
from sklearn.preprocessing import StandardScaler
from matplotlib.colors import ListedColormap
  1. 绘制边界函数
# 边界绘制函数
def plot_decision_boundary(model,axis):
    x0,x1=np.meshgrid(
        np.linspace(axis[0],axis[1],int((axis[1]-axis[0])*100)).reshape(-1,1),
        np.linspace(axis[2],axis[3],int((axis[3]-axis[2])*100)).reshape(-1,1))
    # meshgrid函数是从坐标向量中返回坐标矩阵
    x_new=np.c_[x0.ravel(),x1.ravel()]
    y_predict=model.predict(x_new)#获取预测值
    zz=y_predict.reshape(x0.shape)
    custom_cmap=ListedColormap(['#EF9A9A','#FFF59D'])
    plt.contourf(x0,x1,zz,cmap=custom_cmap)
  1. 导入测试数据
iris = datasets.load_iris()
data_x = iris.data[:, :2] 
data_y = iris.target
  1. 进行数据预处理
scaler=StandardScaler()# 标准化
data_x = scaler.fit_transform(data_x)#计算训练数据的均值和方差
  1. 绘制基本鸢尾花数据集
plt.rcParams["font.sans-serif"] = ['SimHei']    # 用来正常显示中文标签,SimHei是字体名称,字体必须在系统中存在,字体的查看方式和安装第三部分
plt.rcParams['axes.unicode_minus'] = False     # 用来正常显示负号
plt.scatter(data_x[data_y==0, 0],data_x[data_y==0, 1])    # 选取y所有为0的+X的第一列
plt.scatter(data_x[data_y==1, 0],data_x[data_y==1, 1])    # 选取y所有为1的+X的第一列

plt.xlabel('sepal length')    # 设置横坐标标注xlabel为sepal width
plt.ylabel('sepal width')    # 设置纵坐标标注ylabel为sepal length
plt.title('sepal散点图')    # 设置散点图的标题为sepal散点图
plt.show()

1. 线性SVM

from sklearn.svm import LinearSVC
svc_line = LinearSVC(C =1e9,max_iter=1000000) #线性SVM分类器
svc_line.fit(data_x,data_y)#训练svm
plot_decision_boundary(svc_line,axis=[-3,3,-3,4])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])

plt.scatter(data_x[data_y==2,0],data_x[data_y==2,1])
plt.show()

在这里插入图片描述
在这里插入图片描述

  • 可以很明显的看到和第一个决策边界的不同,在第一个决策边界汇总,有一个蓝点是分类错误的,C值越小容错空间越大,越容易出现错误。
  • 我们可以通过svc.coef_ 函数来获取学习到的权重系数,svc.intercept_ 函数获取偏差

2. 多项式核

from sklearn.preprocessing import PolynomialFeatures #导入多项式回归
from sklearn.pipeline import Pipeline #导入python里的管道
def PolynomialSVC(degree,c=5):#多项式svm
    """
    :param d:阶数
    :param C:正则化常数
    :return:一个Pipeline实例
    """
    return Pipeline([
            # 将源数据 映射到 3阶多项式
            ("poly_features", PolynomialFeatures(degree=degree)),
            # 标准化
            ("scaler", StandardScaler()),
            # SVC线性分类器
            ("svm_clf", LinearSVC(C=c, loss="hinge", random_state=10,max_iter=100000))
        ])

poly_svc=PolynomialSVC(degree=5)
poly_svc.fit(data_x,data_y)
plot_decision_boundary(poly_svc,axis=[-3,4,-4,5])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])
plt.scatter(data_x[data_y==2,0],data_x[data_y==2,1])
plt.show()

在这里插入图片描述

3. 高斯核

  1. 一阶段
    在这里插入图片描述
from sklearn.svm import SVC #导入svm
def RBFKernelSVC(gamma=1.0):
    return Pipeline([
        ('std_scaler',StandardScaler()),
        ('svc',SVC(kernel='rbf',gamma=gamma))
    ])
svc=RBFKernelSVC(gamma=42)#gamma参数很重要,gamma参数越大,支持向量越小
svc.fit(data_x,data_y)
plot_decision_boundary(svc,axis=[-3,3,-3,4])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])
plt.scatter(data_x[data_y==2,0],data_x[data_y==2,1])
plt.show()
  1. 二阶段
    在这里插入图片描述
from sklearn.svm import SVC #导入svm
def RBFKernelSVC(gamma=1.0):
    return Pipeline([
        ('std_scaler',StandardScaler()),
        ('svc',SVC(kernel='rbf',gamma=gamma))
    ])
svc=RBFKernelSVC(gamma=500)#gamma参数很重要,gamma参数越大,支持向量越小
svc.fit(data_x,data_y)
plot_decision_boundary(svc,axis=[-3,3,-3,4])
plt.scatter(data_x[data_y==0,0],data_x[data_y==0,1])
plt.scatter(data_x[data_y==2,0],data_x[data_y==2,1])
plt.show()

gamma取值越大,就是高斯分布的钟形图越窄,这里相当于每个样本点都形成了钟形图。很明显这样是过拟合的

四、示例重做

import numpy as np 
import matplotlib.pyplot as plt 
from sklearn import datasets 
from sklearn.preprocessing import StandardScaler 
from sklearn.svm import LinearSVC 
iris = datasets.load_iris()

X = iris.data
y = iris.target

X = X [y<2,:2] #只取y<2的类别,也就是0 1 并且只取前两个特征
y = y[y<2] # 只取y<2的类别

# 分别画出类别0和1的点
plt.scatter(X[y==0,0],X[y==0,1],color='red') 
plt.scatter(X[y==1,0],X[y==1,1],color='blue')
plt.show()

在这里插入图片描述

  1. 高斯核
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-4,5,1)#生成测试数据
y = np.array((x >= -2 ) & (x <= 2),dtype='int')

plt.scatter(x[y==0],[0]*len(x[y==0]))# x取y=0的点, y取0,有多少个x,就有多少个y
plt.scatter(x[y==1],[0]*len(x[y==1]))
plt.show()

在这里插入图片描述

def gaussian(x,l):
    gamma = 1.0
    return np.exp(-gamma * (x -l)**2)
l1,l2 = -1,1
X_new = np.empty((len(x),2)) #len(x) ,2
for i,data in enumerate(x):
    X_new[i,0] = gaussian(data,l1)
    X_new[i,1] = gaussian(data,l2)
plt.scatter(X_new[y==0,0],X_new[y==0,1])
plt.scatter(X_new[y==1,0],X_new[y==1,1])
plt.show()

在这里插入图片描述

五、总结

  • 在此阶段中,通过对于核函数的调试,使得数据集进行更明确的划分,但是当参数过大,训练数据集较为困难,则会产生过拟合等情况
  • SVM使用核函数可以向高维空间进行映射,并可以解决非线性分类,以此达到较好的分类效果。

六、参考

【机器学习】机器学习之支持向量机(SVM)
基于jupyter notebook的python编程-----支持向量机学习二(SVM处理线性[鸢尾花数据集]和非线性数据集[月亮数据集])
机器学习–支持向量机 (SVM)算法的原理及优缺点
《机器学习》分析鸢尾花数据集
SVM
核函数(Kernel function)(举例说明,通俗易懂)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值