SVM支持向量机+实例展示

一、SVM简介

SVM定义:支持向量机(英语:support vector machine,常简称为SVM,又名支持向量网络)是在分类与回归分析中分析数据的监督式学习模型与相关的学习算法。给定一组训练实例,每个训练实例被标记为属于两个类别中的一个或另一个,SVM训练算法创建一个将新的实例分配给两个类别之一的模型,使其成为非概率二元线性分类器。SVM模型是将实例表示为空间中的点,这样映射就使得单独类别的实例被尽可能宽的明显的间隔分开。然后,将新的实例映射到同一空间,并基于它们落在间隔的哪一侧来预测所属类别。简言之,SVM就是一种二类分类模型,他的基本模型是定义在特征空间的间隔最大的线性分类器,SVM的学习策略就是间隔最大化。

支持向量机思想:为了把两组数据分开,在空心点的类别找到一个或多个点离实心点最近,在实心点中找到一个或多个点与空心点最近,分类实心和空心点取决于这些边界上的点而与离边界较远的点,即在分割两类别点的时候,只需要考虑支持向量,通过支持向量确定分割直线。假设此直线有宽度,左边贴合一个边界点,右边贴和另一组,实现把点分开并且宽度最大。关键取决于w方向,通过将x1、x2、x3三点代入wx+b=1/-1中求出w和b的值。推导过程如下:

向量内积知识点回顾:

二、SVM数学模型:

 \min_{w,b} \frac{1}{2}w^{T}w

s.t.  y_i{}(w^T{}X_i+b)\geqslant 1, i=1,……,n

h(x) = sign(w^T{}x+b  sign表示求符号

首先强调,在机器学习领域中没有一种算法或模型在所有情况下比其他的好。

在现实数据中分割很难分的很干净,会出现以下几种情况:

这时需要放宽标准,即创建带松弛变量的SVM数学模型:(每个样本都有一个\varepsilon,c如果很大,分割线会尽量满足原始SVM定义;c如果c很小则真正使松弛变量起作用)

y_i{}(w^T{} x_{i}+b)\geq 1-\varepsilon _{i}   ——>  \varepsilon _{i}\geq 1-y_{i}(w^Tx_i+b)  ——>\varepsilon _i=max(0,1-y_i(w^Tx_i+b))  合页损失函数

Hinge Loss(合页损失函数)

合页损失函数的性质:

1、合页损失函数是凸函数,容易优化;

2、在自变量小于0的部分梯度比较小,对错误分类的惩罚较轻;

3、在自变量大于等于1的部分,值为0:只要对某个数据分类是正确的,并且正确的可能性足够高,那么就用不着针对这个数据进一步优化了;

4、在自变量等于0时不可导,需要分段求导;

5、使得在求解最优化时,只有支持向量会参与确定分界线,而且支持向量的个数远小于训练数据的个数。

三、求解SVM

求解SVM即求解w、b:

方法一:二次规划,经典运筹学的最优化问题,可以在多项式时间内求得最优解(Python中有工具包)

方法二:转换为对偶问题

四、扩展SVM到支持多个类别

由于SVM是一种二元分类器,即用一条线或一个平面分开两类不同数据,如何让其支持多个类别呢?

方法一:OVR(one wersus rest)对于K个类别的情况,训练K个SVM,第j个SVM用于判断任意条数据是属于类别j还是类别非j。预测的时候,具有最大值的W_i^Tx表示给定的数据x属于类别i。

方法二:OVO(one versus one),对于K个类别的情况,训练K*(K-1)/2个SVM,每一个SVM只用于判断任意条数据是属于K中的特定两个类别。预测的时候,使用K*(K-1)/2个SVM做K*(K-1)/2次预测,使用计票的方式决定数据被分类为哪个类别的次数最多,就认为数据x属于此类别。

五、核函数

为什么要使用核函数——处理线性不可分情况。

显然在这种情况下我们需要非线性分类器,线性分类器无法解决这种特殊情况。解决方法是将特征映射到更高的维度,如下图所示:

成为核函数的条件:1、为对称矩阵;2、为半正定矩阵

六、SVM总结

1、SVM专注于找最优分界线,用于减小过拟合;

2、核函数的应用使得SVM可以高效的用于非线性可分的情况;

优点:

  • 模型只需要保存支持向量, 模型占用内存少, 预测快.
  • 分类只取决于支持向量, 适合数据的维度高的情况, 例如DNA数据

缺点:

  • 训练的时间复杂度为  \sigma [N^3]或者至少 \sigma [N^2], 当数据量巨大时候不合适使用。
  • 需要做调参C当数据量大时非常耗时间。

七、实例

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# use seaborn plotting defaults
import seaborn as sns; sns.set()

创建模拟数据集

from sklearn.datasets.samples_generator import make_blobs
X, y = make_blobs(n_samples=50, centers=2,
                  random_state=0, cluster_std=0.60)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn');

可以有多种方法分类

xfit = np.linspace(-1, 3.5)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')

for m, b in [(1, 0.65), (0.5, 1.6), (-0.2, 2.9)]:
    plt.plot(xfit, m * xfit + b, '-k')

plt.xlim(-1, 3.5);

SVM: 假想每一条分割线是有宽度的

xfit = np.linspace(-1, 3.5)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')

for m, b, d in [(1, 0.65, 0.33), (0.5, 1.6, 0.55), (-0.2, 2.9, 0.2)]:
    yfit = m * xfit + b
    plt.plot(xfit, yfit, '-k')
    plt.fill_between(xfit, yfit - d, yfit + d, edgecolor='none',
                     color='#AAAAAA', alpha=0.4)

plt.xlim(-1, 3.5);

 

在SVM的框架下, 认为最宽的线为最优的分割线

训练SVM

使用线性SVM和比较大的 C


from sklearn.svm import SVC # "Support vector classifier"
model = SVC(kernel='linear', C=1E10)
model.fit(X, y)
SVC(C=10000000000.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
  kernel='linear', max_iter=-1, probability=False, random_state=None,
  shrinking=True, tol=0.001, verbose=False)

 

创建一个显示SVM分割线的函数

def plot_svc_decision_function(model, ax=None, plot_support=True):
    """Plot the decision function for a 2D SVC"""
    if ax is None:
        ax = plt.gca()
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    
    # create grid to evaluate model
    x = np.linspace(xlim[0], xlim[1], 30)
    y = np.linspace(ylim[0], ylim[1], 30)
    Y, X = np.meshgrid(y, x)
    xy = np.vstack([X.ravel(), Y.ravel()]).T
    P = model.decision_function(xy).reshape(X.shape)
    
    # plot decision boundary and margins
    ax.contour(X, Y, P, colors='k',
               levels=[-1, 0, 1], alpha=0.5,
               linestyles=['--', '-', '--'])
    
    # plot support vectors
    if plot_support:
        ax.scatter(model.support_vectors_[:, 0],
                   model.support_vectors_[:, 1],
                   s=300, linewidth=1, facecolors='none');
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
plot_svc_decision_function(model);

model.support_vectors_
array([[0.44359863, 3.11530945],
       [2.33812285, 3.43116792],
       [2.06156753, 1.96918596]])

非支持向量的数据, 对分割线没有影响

只有支持向量会影响分割线, 如果我们添加一些非支持向量的数据, 对分割线没有影响

def plot_svm(N=10, ax=None):
    X, y = make_blobs(n_samples=200, centers=2,
                      random_state=0, cluster_std=0.60)
    X = X[:N]
    y = y[:N]
    model = SVC(kernel='linear', C=1E10)
    model.fit(X, y)
    
    ax = ax or plt.gca()
    ax.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='autumn')
    ax.set_xlim(-1, 4)
    ax.set_ylim(-1, 6)
    plot_svc_decision_function(model, ax)

fig, ax = plt.subplots(1, 2, figsize=(16, 6))
fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)
for axi, N in zip(ax, [60, 120]):
    plot_svm(N, axi)
    axi.set_title('N = {0}'.format(N))

使用SVM进行人脸识别

from sklearn.datasets import fetch_lfw_people
faces = fetch_lfw_people(min_faces_per_person=60)
print(faces.target_names)
print(faces.images.shape)
['Ariel Sharon' 'Colin Powell' 'Donald Rumsfeld' 'George W Bush'
 'Gerhard Schroeder' 'Hugo Chavez' 'Junichiro Koizumi' 'Tony Blair']
(1348, 62, 47)

 

人脸实例

fig, ax = plt.subplots(3, 5)
for i, axi in enumerate(ax.flat):
    axi.imshow(faces.images[i], cmap='bone')
    axi.set(xticks=[], yticks=[],
            xlabel=faces.target_names[faces.target[i]])

每一幅图的尺寸为 [62×47] , 大约 3000 个像素值

我们可以将整个图像展平为一个长度为3000左右的一维向量, 然后使用这个向量做为特征. 通常更有效的方法是通过预处理提取图像最重要的特征. 一个重要的特征提取方法是PCA(主成分分析), 可以将一副图像转换为一个长度为更短的(150)向量.

from sklearn.svm import SVC
from sklearn.decomposition import PCA
from sklearn.pipeline import make_pipeline
pca = PCA(n_components=150, whiten=True, random_state=42)
svc = SVC(kernel='linear', class_weight='balanced')
model = make_pipeline(pca, svc)

 

将数据分为训练和测试数据集

from sklearn.model_selection import train_test_split
Xtrain, Xtest, ytrain, ytest = train_test_split(faces.data, faces.target,
                                                random_state=42)

调参:通过交叉验证寻找最佳的 C (控制间隔的大小)

from sklearn.model_selection import GridSearchCV

param_grid = {'svc__C': [1, 5, 10, 50]}
grid = GridSearchCV(model, param_grid)

%time grid.fit(Xtrain, ytrain)
print(grid.best_params_)

 

CPU times: user 7.56 s, sys: 157 ms, total: 7.72 s Wall time: 3.98 s {'svc__C': 1}

model = grid.best_estimator_
yfit = model.predict(Xtest)

使用训练好的SVM做预测

fig, ax = plt.subplots(4, 6)
for i, axi in enumerate(ax.flat):
    axi.imshow(Xtest[i].reshape(62, 47), cmap='bone')
    axi.set(xticks=[], yticks=[])
    axi.set_ylabel(faces.target_names[yfit[i]].split()[-1],
                   color='black' if yfit[i] == ytest[i] else 'red')
fig.suptitle('Predicted Names; Incorrect Labels in Red', size=14);

 

生成性能报告

from sklearn.metrics import classification_report
print(classification_report(ytest, yfit,
                            target_names=faces.target_names))
                   precision    recall  f1-score   support

     Ariel Sharon       0.62      0.67      0.65        15
     Colin Powell       0.74      0.84      0.79        68
  Donald Rumsfeld       0.74      0.81      0.77        31
    George W Bush       0.85      0.79      0.82       126
Gerhard Schroeder       0.75      0.78      0.77        23
      Hugo Chavez       0.93      0.70      0.80        20
Junichiro Koizumi       0.92      0.92      0.92        12
       Tony Blair       0.81      0.83      0.82        42

        micro avg       0.80      0.80      0.80       337
        macro avg       0.80      0.79      0.79       337
     weighted avg       0.80      0.80      0.80       337

混淆矩阵

from sklearn.metrics import confusion_matrix
mat = confusion_matrix(ytest, yfit)
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False,
            xticklabels=faces.target_names,
            yticklabels=faces.target_names)
plt.xlabel('true label')
plt.ylabel('predicted label');

 

——以上为笔者在贪心学院《机器学习特训营》第五章课程中的学习笔记

  • 70
    点赞
  • 395
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值