机器学习基础-SVM算法解析

6 篇文章 0 订阅
1 篇文章 0 订阅

1 概念

超平面:超平面是平面的一般化

  • 在一维的平面中,它是点
  • 在二维的平面中,它是线
  • 在三维的平面中,它是面
  • 在更高的维度中,我们称之为超平面

分离超平面:将两类数据进行分离的超平面,分离超平面一般会有多个
间隔:超平面与和它最接近的数据点之间的距离。那么间隔(Margin)就是二倍的这个距离

2 SVM原理

支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机。
目的是用训练数据集的间隔最大化找到一个最优分离超平面。
即:

  • 找到一条分界线(二维)或一条流形(高维),从而达到分类的目的。
  • 使用最靠近分界线的点作为support vectors。

如何确定最大化间隔

  1. 找到两个平行超平面,可以划分数据集并且两平面之间没有数据点, 两个平行超平面的表示 w x i − b > = 1 wx_i - b>=1 wxib>=1 w x i − b < = − 1 wx_i - b<=-1 wxib<=1,即 y i ( w x i − b ) > = 1 y_i(wx_i - b) >= 1 yi(wxib)>=1
  2. 最大化上述两个超平面, 最大化间隔 m = 2 ∣ ∣ w ∣ ∣ m=\frac{2}{||w||} m=w2, 其中 ∣ ∣ w ∣ ∣ = w 1 2 + w 2 2 ||w||=\sqrt{w_1^2+w_2^2} w=w12+w22 ,即w的模越小,m越大
  3. 确定目标,在约束条件 y i ( w x i − b ) > = 1 y_i(wx_i - b) >= 1 yi(wxib)>=1下,找到使||w||最小的w和b,我们的最优分离超平面就确定了

上面的最优超平面问题是一个凸优化问题,可以转换成了拉格朗日的对偶问题,判断是否满足KKT条件,然后求解。

最终分类超平面的确定依赖于部分极限位置的样本点,这叫做支持向量

由于支持向量在确定分离超平面中起着决定性作用,所有将这类模型叫做支持向量机

分类:

  • Hard-Margin SVM,硬间隔线性SVM
  • Soft-Margin SVM,软间隔线性SVM
  • Kernel SVM,非线性核函数SVM
  • 多分类SVM

3 SVM分类

3.1 硬间隔线性SVM

样本点都是线性可分的,我们就可以通过分类将样本点完全分类准确,不存在分类错误的情况,这种叫硬间隔,这类模型叫做硬间隔线性SVM。
优缺点:

  • 不适用于线性不可分数据集。
  • 对离群点(outlier)敏感
3.2 软间隔线性SVM

可以通过分类将样本点不完全分类准确,存在少部分分类错误的情况,这叫软间隔,这类模型叫做软间隔线性SVM。软间隔对约束条件进行改造,迫使某些不满足约束条件的点作为损失函数。
此时求解的最大间隔为:
在这里插入图片描述

3.3 核函数

对于样本点并不是线性可分的,无法用以上线性SVM分离,所以我们需要一种方法,可以将样本从原始空间映射到一个更高纬的空间中,使得样本在新的空间中线性可分,即:核函数。在非线性SVM中,核函数的选择关系到SVM的分类效果。
多种核函数:线性核函数、多项式核函数、高斯核函数、sigmoid核函数等等,甚至你还可以将这些核函数进行组合,以达到最优线性可分的效果

公式推导见 手撕SVM公式——硬间隔、软间隔、核技巧

3.4 多分类SVM

多分类应该怎么分呢?有两种方法:一对多和一对一
一对多法
一对多法讲究的是将所有的分类分成两类:一类只包含一个分类,另一类包含剩下的所有分类
举个例子:现在有A、B、C、D四种分类,根据一对多法可以这样分:
①:样本A作为正集,B、C、D为负集
②:样本B作为正集,A、C、D为负集
③:样本C作为正集,A、B、D为负集
④:样本D作为正集,A、B、C为负集
在这里插入图片描述
该方法分类速度较快,但训练速度较慢,添加新的分类,需要重新构造分类器。

一对一法
一对一法讲究的是从所有分类中只取出两类,一个为正类一个为父类
再举个例子:现在有A、B、C三种分类,根据一对一法可以这样分:
①分类器:样本A、B
②分类器:样本A、C
③分类器:样本B、C
在这里插入图片描述
该方法的优点是:当新增一类时,只需要训练与该类相关的分类器即可,训练速度较快。缺点是:当类的种类K很多时,分类器个数K(K-1)/2会很多,训练和测试时间较慢。

4 API

SVC的参数解析:

from sklearn.svm import SVM

model = SVC(kernel=‘rbf’, C=1.0, gamma=0.001)

  • kernel代表核函数的选择,有四种选择,默认rbf(即高斯核函数)
  • 参数C代表目标函数的惩罚系数,默认情况下为 1.0
  • 参数gamma代表核函数的系数,默认为样本特征数的倒数

其中kernel代表的四种核函数分别是:

  • linear:线性核函数,在数据线性可分的情况下使用的
  • poly:多项式核函数,可以将数据从低维空间映射到高维空间
  • rbf:高斯核函数,同样可以将样本映射到高维空间,但所需的参数较少,通常性能不错
  • sigmoid:sigmoid核函数,常用在神经网络的映射中

5 代码实现

from sklearn.datasets import load_breast_cancer
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np
from time import time
import datetime
 
data = load_breast_cancer()
X = data.data
y = data.target
 
np.unique(y) #查看label都由哪些分类
plt.scatter(X[:,0], X[:,1],c=y)
plt.show()
 
 
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, y, test_size=0.3, random_state=420)
kernel = ["linear","poly","rbf", "sigmod"]
for kernel in kernel:
    time0 = time()
    clf = SVC(kernel = kernel, gamma = "auto", cache_size=5000).fit(Xtrain,Ytrain) #cache_size default=200 默认使用200MB内存
    print("The accuracy under kernel %s is %f" % (kernel, clf.score(Xtest, Ytest)))
    print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))
 
#poly多项式核函数太浪费时间了,不能用
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, y, test_size=0.3, random_state=420)
kernel = ["linear","rbf", "sigmoid"]
for kernel in kernel:
    time0 = time()
    clf = SVC(kernel = kernel, gamma = "auto", cache_size=5000).fit(Xtrain,Ytrain) #cache_size default=200 默认使用200MB内存
    print("The accuracy under kernel %s is %f" % (kernel, clf.score(Xtest, Ytest)))
    print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))
 
 
#到此应该可以确定乳腺癌数据集应该是一个线性可分的数据集
 
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, y, test_size=0.3, random_state=420)
kernel = ["linear","poly","rbf", "sigmoid"]
for kernel in kernel:
    time0 = time()
    clf = SVC(kernel = kernel, 
              degree = 1, #degree默认值是3,所以poly核函数跑的非常慢,
              gamma = "auto", 
              cache_size=5000).fit(Xtrain,Ytrain) #cache_size default=200 默认使用200MB内存
    print("The accuracy under kernel %s is %f" % (kernel, clf.score(Xtest, Ytest)))
    print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))
 
# rbf 表现不应该这么差的,应该可以调整参数,对数据进行预处理,提高其准确性
 
import pandas as pd
data = pd.DataFrame(X)
 
data.describe([0.01,0.05,0.1,0.25,0.5,0.75,0.9,0.99]).T
 
#数据存在问题:
# (1)查看数据均值mean 和 std 发现,数据量纲不统一
# (2) 数据的分布是偏态的 
# 因此我们需要对数据进行标准化
from sklearn.preprocessing import StandardScaler #让数据服从标准分布的标准化
X = StandardScaler().fit_transform(X)
data = pd.DataFrame(X)
data.describe([0.01,0.05,0.1,0.25,0.5,0.75,0.9,0.99]).T
 
#数据处理之后,再跑一遍
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X, y, test_size=0.3, random_state=420)
kernel = ["linear","poly","rbf", "sigmoid"]
for kernel in kernel:
    time0 = time()
    clf = SVC(kernel = kernel, 
              degree = 1, #degree默认值是3,所以poly核函数跑的非常慢,
              gamma = "auto", 
              cache_size=5000).fit(Xtrain,Ytrain) #cache_size default=200 默认使用200MB内存
    print("The accuracy under kernel %s is %f" % (kernel, clf.score(Xtest, Ytest)))
    print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))
 
# fine tune rbf parameter gamma
score = []
gamma_range = np.logspace(-10,1,50)
for i in gamma_range:
    clf = SVC(kernel="rbf", gamma=i, cache_size=5000).fit(Xtrain,Ytrain)
    score.append(clf.score(Xtest, Ytest))
    
print(max(score), gamma_range[score.index(max(score))])
plt.plot(gamma_range, score)
plt.show()
#其实到这里可以看到rbf的精度已经跟linear一致了,但是rbf核函数算的明显要快很多,所以用SVM大部分情况下,都使用rbf核函数
 
plt.plot(range(50), np.logspace(-10,1,50))
plt.show()
 
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.model_selection import GridSearchCV
time0 = time()
gamma_range = np.logspace(-10, 1, 20)
coef0_range = np.linspace(0,5, 10)
param_grid = dict(gamma = gamma_range, coef0 = coef0_range)
cv = StratifiedShuffleSplit(n_splits = 5, test_size = 0.3, random_state=420)
grid = GridSearchCV(SVC(kernel="poly", degree=1, cache_size=5000),param_grid=param_grid, cv=cv)
grid.fit(X,y)
print("The best parameters are %s with score %0.5f" % (grid.best_params_,grid.best_score_))
print(datetime.datetime.fromtimestamp(time()-time0).strftime("%M:%S:%f"))
 
#软间隔系数C 的调教, c默认1,必须是一个大于0 的数字
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值