SVM支持向量机

  • 1. 线性SVM
    • 1.1 从Logistic回归出发
    • 1.2 大边界分类与SVM
    • 1.3 调整正则化参数
  • 2. 非线性SVM(高斯核函数)
    • 2.1 高斯核
    • 2.2 非线性分类
    • 2.3 参数搜索

数据集、源文件可以在Github项目中获得
链接: https://github.com/Raymond-Yang-2001/AndrewNg-Machine-Learing-Homework

1. 线性SVM

1.1 从Logistic回归出发

在Logistic回归进行分类的时候,我们有 h θ ( x ) = σ ( θ ⊤ x ) h_{\theta}(x)=\sigma(\theta^{\top} x) hθ​(x)=σ(θ⊤x),其中 σ \sigma σ代表了sigmoid函数。Logisit回归在进行分类的时候,会使得正类的 θ ⊤ x ≥ 0 \theta^{\top}x\ge 0 θ⊤x≥0,负类的 θ ⊤ x < 0 \theta^{\top}x < 0 θ⊤x<0。其损失函数如下:
J ( θ ) = 1 m ∑ i = 1 m − y ( i ) log ⁡ ( h θ ( x ( i ) ) ) − ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) J(\theta)=\frac{1}{m}\sum_{i=1}^{m}{-y^{(i)}\log{(h_{\theta}(x^{(i)}))}}-(1-y^{(i)})\log{(1-h_{\theta}(x^{(i)}))} J(θ)=m1​i=1∑m​−y(i)log(hθ​(x(i)))−(1−y(i))log(1−hθ​(x(i)))
其中, − log ⁡ h θ ( x ) -\log{h_\theta(x)} −loghθ​(x)和 − log ⁡ ( 1 − h θ ( x ) ) -\log{(1-h_{\theta}(x))} −log(1−hθ​(x))的函数图像如下所示:

对损失函数做如下修改,使得在 y = 1 y=1 y=1的时候,期望的 θ ⊤ x ≫ 1 \theta^{\top}x\gg 1 θ⊤x≫1而不是 θ ⊤ x ≫ 0 \theta^{\top}x\gg 0 θ⊤x≫0;在 y = 0 y=0 y=0的时候,期望的 θ ⊤ x ≪ − 1 \theta^{\top}x\ll -1 θ⊤x≪−1而不是 θ ⊤ x ≪ 0 \theta^{\top}x\ll 0 θ⊤x≪0。

这就得到了线性SVM的一般损失函数:
J ( θ ) = C ∑ i = 1 m [ y ( i ) c o s t 1 ( θ ⊤ x ) + ( 1 − y ( i ) ) c o s t 0 ( θ ⊤ x ) ] + 1 2 ∑ j = 1 n θ j 2 J(\theta)=C\sum_{i=1}^{m}{[y^{(i)}\mathrm{cost}_{1}(\theta^{\top}x)+(1-y^{(i)})\mathrm{cost}_{0}(\theta^{\top}x)]}+\frac{1}{2}\sum_{j=1}^{n}{\theta_{j}^{2}} J(θ)=Ci=1∑m​[y(i)cost1​(θ⊤x)+(1−y(i))cost0​(θ⊤x)]+21​j=1∑n​θj2​
这里的C是正则化参数。

在线性SVM中,区别于Logistic回归输出分类概率,我们假设:
{ h θ ( x ) = 1 , θ ⊤ x ≥ 0 h θ ( x ) = 0 , e l s e \left\{ \begin{aligned} &h_{\theta}(x)=1,\quad\theta^{\top}x\ge0 \\ &h_{\theta}(x)=0,\quad\mathrm{else}\\ \end{aligned} \right. {​hθ​(x)=1,θ⊤x≥0hθ​(x)=0,else​
也就是说,SVM分类器直接输出分类结果。

1.2 大边界分类与SVM

前文所述,在SVM中,最小化代价函数的必要条件是,在 y = 1 y=1 y=1的时候,期望的 θ ⊤ x ≥ 1 \theta^{\top}x\ge 1 θ⊤x≥1而不是 θ ⊤ x ≥ 0 \theta^{\top}x\ge 0 θ⊤x≥0;在 y = 0 y=0 y=0的时候,期望的 θ ⊤ x ≪ − 1 \theta^{\top}x\ll -1 θ⊤x≪−1而不是 θ ⊤ x < 0 \theta^{\top}x< 0 θ⊤x<0。事实上,使用0作为分类边界已经能很好的区分进行分类了,SVM将这个分类边界进一步“加宽”,从0变成了(-1,1),我们将SVM称作一种大边界的分类器

考虑线性SVM的损失函数,假设我们找到了符合上述条件的 θ \theta θ,那么在任何情况下,损失函数的前半部分都为0,也就是说优化目标可以简化为:
min ⁡ 1 2 ∑ j = 1 n θ j 2 = 1 2 ∣ ∣ θ ∣ ∣ 2 s . t . { θ ⊤ x ( i ) ≥ 1 , y ( i ) = 1 θ ⊤ x ( i ) ≤ − 1 , y ( i ) = 0 \min{\frac{1}{2}\sum_{j=1}^{n}{\theta_{j}^{2}}=\frac{1}{2}||\theta||^{2}} \\ \mathrm{s.t.}\left\{ \begin{aligned} &\theta^{\top}x^{(i)}\ge1,\quad y^{(i)}=1 \\ &\theta^{\top}x^{(i)}\le-1,\quad y^{(i)}=0 \\ \end{aligned} \right. min21​j=1∑n​θj2​=21​∣∣θ∣∣2s.t.{​θ⊤x(i)≥1,y(i)=1θ⊤x(i)≤−1,y(i)=0​

由线性代数知识可知: θ ⊤ x ( i ) = ρ ( i ) ∣ ∣ θ ∣ ∣ \theta^{\top}x^{(i)}=\rho^{(i)}||\theta|| θ⊤x(i)=ρ(i)∣∣θ∣∣, ρ ( i ) \rho^{(i)} ρ(i)是 x ( i ) x^{(i)} x(i)在 θ \theta θ方向上的投影长度。
设我们的一种决策边界如下,蓝色线是 θ \theta θ方向,与其垂直的绿色线是决策边界:

在这种情况下, ρ \rho ρ比较小,为了满足 ρ ( i ) ∣ ∣ θ ∣ ∣ ≥ 1 \rho^{(i)}||\theta||\ge1 ρ(i)∣∣θ∣∣≥1或者 ρ ( i ) ∣ ∣ θ ∣ ∣ ≤ − 1 \rho^{(i)}||\theta||\le-1 ρ(i)∣∣θ∣∣≤−1, ∣ ∣ θ ∣ ∣ ||\theta|| ∣∣θ∣∣要变得很大才可以满足。显然,这会使得损失函数值变大,与优化目标相反。

考虑另一种决策边界:

在这种情况下, ρ \rho ρ会变大,相应的 ∣ ∣ θ ∣ ∣ ||\theta|| ∣∣θ∣∣可以变得比较小。通过让间距变大,即通过这些 ρ \rho ρ等等的值,支持向量机最终可以找到一个较小的范数。这正是支持向量机中最小化目标函数的目的,也就是为什么支持向量机最终会找到大间距分类器的原因。因为它试图极大化这些 ρ \rho ρ的范数,它们是训练样本到决策边界的距离。

1.3 调整正则化参数

使用的数据集可视化如下:

使用正则化参数C=1

from sklearn import svm
svc = svm.LinearSVC(C=1, max_iter=1000)
svc.fit(x,y.ravel())
theta1 = [svc.intercept_[0], svc.coef_[0,0], svc.coef_[0,1]]x_ax = np.arange(0, 4, 0.1)
xx = np.array([1.5,2.5])
y_ax = -theta1[0] / theta1[2] + (-theta1[1] / theta1[2])*x_ax
print(theta1[0],-theta1[0] / theta1[2],-theta1[1] / theta1[2])
yy = (theta1[2] / theta1[1] )*xx
plt.figure(figsize=(10,8))
plt.scatter(x=positive_data[:, 0], y=positive_data[:, 1], s=10, color="red",label="positive")
plt.scatter(x=negative_data[:, 0], y=negative_data[:, 1], s=10, label="negative")
plt.plot(x_ax, y_ax, label="Decision Boundary")
plt.plot(xx, yy, label="Direction of Theta Vector")
plt.axis('equal')
plt.legend(loc='best',framealpha=0.5)
plt.show()

可以看到SVM学习到了一个较好的分类器,没有受到左上角异常值的影响。

正则化参数C=1000

from sklearn import svm
svc2 = svm.LinearSVC(C=100, max_iter=100000)
svc2.fit(x,y.ravel())
theta2 = [svc2.intercept_[0], svc2.coef_[0,0], svc2.coef_[0,1]]
x_ax = np.arange(0, 4, 0.1)y_ax = -theta2[0] / theta2[2] + (-theta2[1] / theta2[2])*x_axplt.figure(figsize=(10,8))
plt.scatter(x=positive_data[:, 0], y=positive_data[:, 1], s=10, color="red",label="positive")
plt.scatter(x=negative_data[:, 0], y=negative_data[:, 1], s=10, label="negative")
plt.plot(x_ax, y_ax, label="Decision Boundary")xx = np.array([1,1.5])
yy = (theta2[2] / theta2[1] )*xx
plt.plot(xx + 1, yy, label="Direction of Theta Vector")plt.axis('equal')
plt.legend(loc=0,framealpha=0.5)
plt.show()


可以看到,在C较大的情况下,SVM受到了离群值的影响,出现了过拟合的现象。

2. 非线性SVM(高斯核函数)

之前讨论的线性SVM,其优化目标的计算是基于 θ ⊤ x \theta^{\top}x θ⊤x的线性运算,当我们面对较复杂的决策边界的时候,简单的线性运算并不能很好的满足需求。就像在神经网络中引入非线性的激励函数一样,在SVM中,我们也引入非线性的核函数,来实现更复杂的分类。这类SVM叫做非线性SVM。

这相当于使用一系列新的特征来代替原样本,核函数就完成了样本到新特征的非线性映射。
f ( i ) ← x ( i ) f^{(i)} \larr x^{(i)} f(i)←x(i)

2.1 高斯核

f i = s i m ( x , l ( i ) ) = exp ⁡ ( − ∣ ∣ x − l ( i ) ∣ ∣ 2 2 σ 2 ) f_{i}=sim(x,l^{(i)})=\exp{\left(-\frac{||x-l^{(i)}||^{2}}{2\sigma^{2}}\right)} fi​=sim(x,l(i))=exp(−2σ2∣∣x−l(i)∣∣2​)
当 x , l ( i ) x,l^{(i)} x,l(i)相接近的时候,核函数值会接近1;当二者相距比较远的是时候,核函数值会接近0。
f ( i ) = ∣ f 0 ( i ) = 1 f 1 ( i ) = s i m ( x ( i ) , l ( 1 ) ) ⋮ f m ( i ) = s i m ( x ( i ) , l ( m ) ) ∣ f^{(i)}=\left|\begin{aligned} f^{(i)}_{0}&=1 \\ f^{(i)}_{1}=&sim(x^{(i)},l^{(1)}) \\ \vdots&\\ f^{(i)}_{m}=&sim(x^{(i)},l^{(m)}) \end{aligned} \right| f(i)= ​f0(i)​f1(i)​=⋮fm(i)​=​=1sim(x(i),l(1))sim(x(i),l(m))​ ​

优化目标函数变为:
J ( θ ) = C ∑ i = 1 m [ y ( i ) c o s t 1 ( θ ⊤ f ( i ) ) + ( 1 − y ( i ) ) c o s t 0 ( θ ⊤ f ( i ) ) ] + 1 2 ∑ j = 1 n θ j 2 J(\theta)=C\sum_{i=1}^{m}{[y^{(i)}\mathrm{cost}_{1}(\theta^{\top}f^{(i)})+(1-y^{(i)})\mathrm{cost}_{0}(\theta^{\top}f^{(i)})]}+\frac{1}{2}\sum_{j=1}^{n}{\theta_{j}^{2}} J(θ)=Ci=1∑m​[y(i)cost1​(θ⊤f(i))+(1−y(i))cost0​(θ⊤f(i))]+21​j=1∑n​θj2​

当 σ \sigma σ参数较大的时候,特征会变得更加平滑( ∣ ∣ x − l ( i ) ∣ ∣ 2 ||x-l^{(i)}||^{2} ∣∣x−l(i)∣∣2的大小的变化对函数值的变化影响较小),不同样本的区分度会变小,这有利于缓解某些离群点的影响,使得模型的方差变小,减轻过拟合,但是会带来模型的偏差变大;相反,当 σ \sigma σ参数较小的时候,特征会变得区分度更大,使得模型方差变大,偏差减小。

2.2 非线性分类

进行非线性分类的数据集可视化如下所示:

正则化参数为100

def show_boundary(svc, scale, fig_size, fig_dpi, positive_data, negative_data, term):"""Show SVM classification boundary plot:param svc: instance of SVC, fitted and probability=True:param scale: scale for x-axis and y-axis:param fig_size: figure size, tuple (w, h):param fig_dpi: figure dpi, int:param positive_data: positive data for dataset (n, d):param negative_data: negative data for dataset (n, d):param term: width for classification boundary:return: decision plot"""t1 = np.linspace(scale[0, 0], scale[0, 1], 500)t2 = np.linspace(scale[1, 0], scale[1, 1], 500)coordinates = np.array([[x, y] for x in t1 for y in t2])prob = svc.predict_proba(coordinates)idx1 = np.where(np.logical_and(prob[:, 1] > 0.5 - term, prob[:, 1] < 0.5 + term))[0]my_bd = coordinates[idx1]plt.figure(figsize=fig_size, dpi=fig_dpi)plt.scatter(x=my_bd[:, 0], y=my_bd[:, 1], s=10, color="yellow", label="My Decision Boundary")plt.scatter(x=positive_data[:, 0], y=positive_data[:, 1], s=10, color="red", label="positive")plt.scatter(x=negative_data[:, 0], y=negative_data[:, 1], s=10, label="negative")plt.title('Decision Boundary')plt.legend(loc=2)plt.show()from sklearn import svm
from sklearn.metrics import classification_report
svc100 = svm.SVC(C=100, kernel='rbf', gamma=10, probability=True)
svc100.fit(x,y.ravel())
report100 = classification_report(svc100.predict(x),y,digits=4)
print(report100)
show_boundary(svc100, scale=np.array([[0,1],[0.4,1]]), fig_size=fig_size, fig_dpi=fig_dpi,positive_data=positive_data,negative_data=negative_data, term=1e-3)
              precision    recall  f1-score   support0     0.9791    0.9542    0.9665       3931     0.9625    0.9830    0.9726       470accuracy                         0.9699       863macro avg     0.9708    0.9686    0.9696       863
weighted avg     0.9701    0.9699    0.9698       863


正则化参数为1

svc1 = svm.SVC(C=1, kernel="rbf", gamma=10, probability=True)
svc1.fit(x,y.ravel())
report1 = classification_report(svc1.predict(x),y,digits=4)
print(report1)
show_boundary(svc1, scale=np.array([[0,1],[0.4,1]]), fig_size=fig_size, fig_dpi=fig_dpi,positive_data=positive_data,negative_data=negative_data, term=1e-3)
              precision    recall  f1-score   support0     0.8851    0.8582    0.8715       3951     0.8833    0.9060    0.8945       468accuracy                         0.8841       863macro avg     0.8842    0.8821    0.8830       863
weighted avg     0.8841    0.8841    0.8840       863


可以看到,在正则化参数变小的情况下,分类边界变得更加“平滑”。

2.3 参数搜索

在机器学习的应用之中,确定参数是关键的一步,不同的参数会使得算法呈现不同的性能。最常用的一个方法是进行网格搜索GridSearch

在实现网格搜索之前,我们先介绍一种评估模型性能的方法——k折交叉验证。一般情况下,在训练模型的过程中,我们只从训练集中划分出固定的一部分作为验证集;k折交叉验证将训练集划分为k部分,模型训练k次,每次使用其中一个作为验证集,其余作为训练集,用在验证集上的平均评分来评估模型性能。这种方法能够更全面的考虑整个训练集的数据分布,往往比固定验证集更能体现模型的泛化能力。

网格搜索的步骤是:

  1. 对于目标参数给出取值集合,多个参数会组成类似一个“网格”的结构
  2. 对于每个参数值组合,进行k折交叉验证(在sklearn中,默认使用k=5)
  3. 选取平均得分最高的参数组合作为最优参数组合

代码实现如下:

candidate = [0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30, 100]
parameters_grid = np.array([[c, gamma] for c in candidate for gamma in candidate])score_list = []
from sklearn.svm import SVC
from SVM import show_boundary
from sklearn.model_selection import KFold
kf = KFold(n_splits=5)
for param in parameters_grid:score = []for tr_idx, test_idx in kf.split(train_x,train_y):tr_x,tr_y = train_x[tr_idx], train_y[tr_idx]test_x, test_y = train_x[test_idx], train_y[test_idx]svc = SVC(C=param[0], gamma=param[1], probability=True)svc.fit(tr_x, tr_y.ravel())score.append(svc.score(test_x, test_y.ravel()))score_list.append(score)score_arr = np.array(score_list).mean(axis=1)
best_param = parameters_grid[np.argmax(score_arr)]
best_score = score_arr.max()
param_dict = {'C': best_param[0], 'gamma': best_param[1]}
best_svc = SVC(probability=True)
best_svc.set_params(**param_dict)
best_svc.fit(train_x,train_y.ravel())
print("Best parameters C={}, gamma={}, with average precision of {:.4f}".format(best_param[0], best_param[1], best_score))
Best parameters C=30.0, gamma=3.0, with average precision of 0.9244

使用sklearn进行验证

svc = SVC(probability=True)
parameters = {'C': candidate, 'gamma': candidate}
# default 5-fold
clf = GridSearchCV(svc, parameters, n_jobs=-1)
clf.fit(train_x,train_y.ravel())
print("SKlearn result: C={}, gamma={}".format(clf.best_params_.get('C'), clf.best_params_.get('gamma')))
SKlearn result: C=30, gamma=3

可视化数据集和分类边界

吴恩达《机器学习》——SVM支持向量机相关推荐

  1. 吴恩达机器学习7——支持向量机SVM

    吴恩达机器学习7 一.SVM直观理解 1. SVM引入逻辑回归 2. 大边界分类器SVM 3. SVM原理 二.核函数 1. 核函数原理和概念 2. SVM和核函数结合的计算步骤 三.使用SVM 一. ...

  2. 吴恩达机器学习 10.支持向量机

    支持向量机 支持向量机(Support Vector Machine). (一个强大的算法广泛的应用于工业界和学术界 与逻辑回归和神经网络相比,支持向量机,或者简称SVM,在学习复杂的非线性方程时提供 ...

  3. 吴恩达机器学习(十)支持向量机(SVM)

    目录 0. 前言 1. 代价函数(Cost Function) 2. 假设函数(Hypothesis) 3. 范数表示 4. 高斯核函数(Gaussian Kernel) 5. SVM实现多分类 6. ...

  4. 吴恩达机器学习作业Python实现(六):SVM支持向量机

    吴恩达机器学习系列作业目录 1 Support Vector Machines 1.1 Example Dataset 1 %matplotlib inline import numpy as np ...

  5. 吴恩达|机器学习作业目录

    一个多月除了上课自习,就是在coursera和网易云课堂上学习吴恩达机器学习的课程,现在学完了,以下是一个多月来完成的作业目录,整理一下以便使用: 1.0 单变量线性回归 1.1 多变量线性回归 2. ...

  6. 吴恩达机器学习与深度学习作业目录 [图片已修复]

    python3.6 (一) 吴恩达机器学习作业目录 1 吴恩达机器学习作业Python实现(一):线性回归 2 吴恩达机器学习作业Python实现(二):logistic回归 3 吴恩达机器学习作业P ...

  7. 6. 吴恩达机器学习课程-作业6-SVM

    fork了别人的项目,自己重新填写,我的代码如下 https://gitee.com/fakerlove/machine-learning/tree/master/code 代码原链接 文章目录 6. ...

  8. 吴恩达机器学习:week1

    title: 吴恩达机器学习:week1 date: 2019-11-03 17:41:46 categories: 机器学习 tags: 机器学习 第1周 文章目录 第1周 1.1 欢迎 1.2 机 ...

  9. 吴恩达机器学习笔记(自用)

    吴恩达机器学习 机器学习的定义 什么是机器学习? 机器学习算法 1.监督学习(Supervised Learning) 2.无监督学习(Unsupervised Learning) 单变量线性回归 模 ...

  10. 吴恩达机器学习课程笔记(英文授课) Lv.1 新手村(回归)

    目录 1-1机器学习的相关名词 1-2 什么是机器学习? 1.definition 定义 2.主要的机器学习算法的分类 1-3有监督学习及常用算法 1.定义 2.两种数据类型补充:categorica ...

最新文章

  1. 皮尔·卡丹的管理思想精髓:从小做到大
  2. [Zer0pts2020]ROR
  3. MySQL中如何查询数据(下)
  4. spring-mybatis.xml 访问html5,Spring mvc无xml配置及利用JdbcTemplate访问数据库
  5. LeetCode之Nim Game
  6. KMP算法 串模式识别 用nextval[j]改进next[j]
  7. python接口自动化(四十三)-公共模块 pymysql 连接mysql数据库(单独说明)
  8. 技巧:让Eclipse或Flex Builder 支持自动换行。(转)
  9. 3 编程基础 Makefile
  10. 15种音乐效果器合集 ArturiaFX Collection 2021.1 mac版
  11. MES系统软件如何在数控加工车间应用?
  12. mac端本地项目上传到码云
  13. 【Typecho插件】SakuraLoad
  14. Matlab在线运行网址
  15. PHP四端代码,壹脉销客智能名片,全套四端开源代码
  16. 图片base64编码解码
  17. 阿里云视频点播一站式解决解决方案怎么样?
  18. 专访三维空间雷成老师 | 原来水墨画风格的3D建筑动画可以如此惊艳……
  19. Heavy Blue Writeup
  20. 如何利用PS中的钢笔抠图

热门文章

  1. 【Linux】宝塔面板 SSL 证书安装部署
  2. 黄山学院04计算机1班,黄山学院学生在第12届中国大学生计算机设计大赛中获佳绩...
  3. 2000-2020年上市公司环保投资数据(含原始数据和stata代码)
  4. 简述什么是图灵机_带你深入理解图灵机--什么是图灵机、图灵完备
  5. 前端切图案例课程一则-姜威-专题视频课程
  6. 王道计算机组成原理第六章---总线总结
  7. Python转盘游戏
  8. Poj 2010-Moo University - Financial Aid
  9. java csv 引号_csv文本编辑引号问题
  10. 让我摘下星星送给你_抖音摘下星星给你什么歌 抖音想摘下星星给你背景音乐歌曲名...