第十周:支持向量机(SVM)

目录

1. 学习内容

2. 什么是SVM

3. 硬间隔与软间隔

4. 在sklearn中使用SVM进行分类

5. 核函数

6. 用SVM解决线性回归问题

7. 参考文献

1. 学习内容

1. 了解SVM的原理

2. 实现SVM

3. 认识核函数

4. 如何用SVM解决线性回归问题

2. 什么是SVM

要了解什么是SVM,还需要从分类问题中的决策边界不适定问题讲起。我们都知道,一个二分类的模型其决策边界可视化后可以是一个低维度平面或者直线。但是,可以将正样本和负样本完美分隔开的低维平面有很多个,假如每一个平面都对应一个模型,那么我们要如何从中选择最好的那个呢?同一个分类问题可以找到多个决策边界,这就是所谓的不适定问题。这个问题会影响到模型的泛化能力。

逻辑回归模型在解决二分类问题时,其目标函数完全由数据集自身来确定,因此得到的决策边界也是由数据集自身得到的,从而解决了不适定问题。而对于SVM而言,它在解决不适定问题时的做法是:找到一条距离正样本和负样本都最远的直线或平面。更专业一点儿的叫法是边界最大化,边界指的就是决策边界到正负样本的最近距离。之所以要这么规定是因为距离正负样本都最远的决策边界对应的模型容错率更高。

因此,只要我们可以推导出决策边界到正负样本的距离(边界到正样本和负样本的距离是相等的),那么最大化边界问题就变成了一个最优化问题。SVM最优化问题相比于之前的问题都更加复杂,涉及到有限制条件的最优化,对偶化等操作。具体推导过程参考[1]

3. 硬间隔与软间隔

如果一个二分类问题可以找到一条“完美”的决策边界可以将正负样本完全分隔开,那么这种情况就叫做硬间隔。反之,有时候一些二分类问题无论如何也无法找到它的硬间隔,此时我们就要考虑能否在有噪声的情况下找到一条并不完美但是容错率高的边界。这就是软间隔的情况。软间隔体现在数学推倒上其实就是适当削弱了约束条件。具体过程可以参考[2]

4. 在sklearn中使用SVM进行分类

import matplotlib.pyplot as plt
import numpy as np
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 = y[y < 2]

# 由于最大化边界需要计算距离,因此有必要对数据进行标准化和归一化
standardScaler = StandardScaler()
standardScaler.fit(X)
X = standardScaler.transform(X)

svc = LinearSVC(C = 1e9)
svc.fit(X, y)

def plot_svc_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),
    )
    X_new = np.c_[x0.ravel(), x1.ravel()]
    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)
    from matplotlib.colors import ListedColormap
    custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
    plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
    
    # 绘制Margin区域上下两根线
    w = model.coef_[0]
    b = model.intercept_[0]
    
    # w0 * x0 + w1 * x1 + b = +1
    # w0 * x0 + w1 * x1 + b = -1
    plot_x = np.linspace(axis[0],axis[1],200)
    up_y = -w[0]/w[1] * plot_x - b/w[1] + 1/w[1]
    down_y = -w[0]/w[1] * plot_x - b/w[1] - 1/w[1]
    
    up_index = (up_y >= axis[2]) & (up_y <= axis[3])
    down_index = (down_y >= axis[2]) & (down_y <= axis[3])
    plt.plot(plot_x[up_index], up_y[up_index], color='black')
    plt.plot(plot_x[down_index], down_y[down_index], color='black')
    
plot_svc_decision_boundary(svc, axis=[-3, 3, -3, 3])
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()
图4.1 分类效果(C=1e9)
图4.2 分类效果(C=0.01)

5. 核函数

SVM不仅可以解决线性分类问题,非线性的分类问题也一样可以解决。SVM处理非线性数据最典型的思路就是使用多项式的方式:扩充原本数据,制造新的多项式特征[3],而扩充数据特征的函数就叫做核函数。

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 matplotlib.colors import ListedColormap

X, y = datasets.make_moons(noise = 0.20, random_state = 123)

def PolynomialSVC(degree, C = 1.0):
    return Pipeline([
        ("poly", PolynomialFeatures(degree = degree)),
        ("std_scaler", StandardScaler()),
        ("linearSVC", LinearSVC(C = C))
    ])

poly_svc = PolynomialSVC(degree = 3)
poly_svc.fit(X,y)

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),
    )
    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, linewidth = 5, cmap = custom_cmap)

plot_decision_boundary(poly_svc, axis = [-1.5, 2.5, -1, 1.5])
plt.scatter(X[y == 0, 0], X[y == 0, 1])
plt.scatter(X[y == 1, 0], X[y == 1, 1])
plt.show()
图5.1 用SVM解决非线性分类问题

使用不同核函数的SVM相当于把原数据映射到了更高维的空间中,原来的空间无法线性可分的数据在高维空间中就未必仍然线性不可分了。很多人也许会疑惑:核函数会让数据升维,那么算法的复杂度也应该急剧上升,这样做值得吗?实际上,核函数的设计是很有考究的。每一个核函数在处理过数据后,高维中的一些运算实际上是等同于原维度中对数据的计算的。也就是说,时间复杂度的增加是线性的而非指数型的。

关于核函数,更多内容可以参考[4]

6. 用SVM解决线性回归问题

SVM解决线性回归问题的核心思想是:首先,指定一个最大边界的值,然后要让尽可能多的点落在边界内部。此时,取边界中心线所在的直线作为最后的结果。

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import LinearSVR
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

boston = datasets.load_boston()
X = boston.data
y = boston.target
X = X[y < 50]
y = y[y < 50]
X = X[:, 5].reshape(-1, 1)

def StandardLinearSVR(epsilon = 0.1):
    return Pipeline([
        ('std_scaler', StandardScaler()),
        ('linearSVR', LinearSVR(epsilon = epsilon))
    ])
    
svr = StandardLinearSVR()
svr.fit(X, y)
predictions = svr.predict(X)

plt.scatter(X, y, c = 'b')
plt.plot(X, predictions, c = 'r')

plt.show()
图6.1 用SVM解决线性回归问题

7. 参考文献

1. https://mp.weixin.qq.com/s/Bv9lqC-Bf9TWUVSwCbPStA

2. https://mp.weixin.qq.com/s/cFCXL_eBs2QbAwMnmwhkTQ

3. https://mp.weixin.qq.com/s/ZGptc2IYSLsX39rVf05Miw

4. https://mp.weixin.qq.com/s/UX4kmA9189cLMM2PE-zyfA

5. https://mp.weixin.qq.com/s/vFFN2vudI9pTfDWRQQqsyg

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值