写给开发者的机器学习指南(十三)

Using Support Vector Machines (SVM's)

在我们实际使用支持向量机(SVM)之前,我先简要介绍一下SVM是什么。 基本SVM是一个二元分类器,它通过选取代表数据点之间最大间隔的超平面将数据集分成2部分。 SVM采用所谓的“校正率”值。 如果没有完美分割,校正速率允许拾取仍然在该误差率内分裂的超平面。因此,即使在线上存在一些点时,校正速率也允许超平面拟合。 这意味着我们不能为每个案例提出“标准”纠正率。 然而,当数据中没有重叠时,较低的值应该比较高的值更好。

我只是解释了基本的SVM,这是一个二元分类器,但这个相同的想法也可以用于更多的类。但是,现在我们将坚持使用2个类,因为只有2个类已经足够了。在这个例子中,我们将通过几个小例子,表示支持向量机(SVM)将优于其他分类算法,如KNN。 这种方法不同于前面的例子,但将帮助你理解如何使用SVM。

对于每个子示例,我们将提供代码,绘图,在SVM上使用不同参数的几个测试运行以及结果的说明。在第一个例子中,我们将使用GaussianKernel,但是在Smile中有很多其他的内核。 在GaussianKernel旁边,我们将解决PolynomialKernel,因为它与高斯函数有很大不同。我们将为每个示例使用以下基础代码,每个示例只更改filePath和svm结构。

object SupportVectorMachine extendsSimpleSwingApplication {
  def top = newMainFrame {
    title ="SVM Examples"
    //File path(this changes per example)
    valtrainingPath =  "/users/.../ExampleData/SVM_Example_1.csv"
    val testingPath=  "/users/.../ExampleData/SVM_Example_1.csv"
    //Loading ofthe test data and plot generation stays the same
    valtrainingData = getDataFromCSV(new File(path))
    val testingData = getDataFromCSV(newFile(path))
    val plot =ScatterPlot.plot(    trainingData._1, 
                                   trainingData._2, 
                                    '@', 
                                   Array(Color.blue, Color.green)
                                )
   peer.setContentPane(plot)
    //Here we doour SVM fine tuning with possibly different kernels
    val svm = newSVM[Array[Double]](new GaussianKernel(0.01), 1.0,2)
   svm.learn(trainingData._1, trainingData._2)
    svm.finish()
    //Calculate howwell the SVM predicts on the training set
    val predictions= testingData
        ._1
        .map(x=> svm.predict(x))
       .zip(testingData._2)
    val falsePredictions= predictions
        .map(x=> if (x._1 == x._2) 0 else 1 )
   println(falsePredictions.sum.toDouble / predictions.length  
                   * 100 + " % false predicted")
    size = newDimension(400, 400)
  }
  defgetDataFromCSV(file: File): (Array[Array[Double]], Array[Int]) = {
    val source =scala.io.Source.fromFile(file)
    val data =source
        .getLines()
        .drop(1)
        .map(x=> getDataFromString(x))
        .toArray
    source.close()
    val dataPoints= data.map(x => x._1)
    valclassifierArray = data.map(x => x._2)
    return(dataPoints, classifierArray)
  }
  defgetDataFromString(dataString: String): (Array[Double], Int) = {
    //Split thecomma separated value string into an array of strings
    val dataArray:Array[String] = dataString.split(',')
    //Extract thevalues from the strings
    valcoordinates  = Array(dataArray(0).toDouble, dataArray(1).toDouble)
    val classifier:Int = dataArray(2).toInt
    //And returnthe result in a format that can later 
    //easily beused to feed to Smile
    return(coordinates, classifier)
  }

例一:(Gaussian Kernel)

在这个例子中,我们提出了SVM最常用的内核,即高斯内核。 这个例子背后的想法是帮助在这个内核上找到好的输入参数。我们用于这个例子的数据可以在这里下载。

从该图可以清楚地看出,线性回归不起作用。 相反,我们将使用SVM进行预测。在我们给出的第一个代码中,高斯内核的σ为0.01,余量为1.0,类数为2,传递给SVM。 该内核表示SVM将在系统中的数据点对上计算相似性的方式。对于高斯核,使用欧几里得距离的方差。 选择高斯核的具体原因是因为数据不包含诸如线性,多项式或双曲线函数的清楚的结构。 相反,数据聚集在3个组中。

我们在GaussianKernel的构造函数中传递的参数是sigma。 该σ值表示内核的平滑度值。 我们将展示更改此参数会如何影响预测。 作为边际惩罚,我们通过1。该参数定义系统中的向量的余量,因此使得该值更低从而导致更多的边界向量。 我们将展示一组运行和他们的结果在实践中有什么样的效果。注意,s:表示西格玛,c:表示校正惩罚。 百分比表示预测中的误差率,其仅仅是训练后对相同数据集的假预测的百分比。

c, s->

0.001

0.01

0.1

0.2

0.5

1.0

2.0

3.0

10.0

0.001

48.4%

48.4%

48.4%

48.4%

48.4%

48.4%

48.4%

48.4%

48.4%

0.01

48.4%

48.4%

40%

43.8%

48.4%

48.4%

48.4%

48.4%

48.4%

0.1

48.4%

48.4%

12.4%

14.2%

17.4%

48.4%

48.4%

48.4%

48.4%

0.2

48.4%

45.6%

9.1%

10.1%

12.3%

48.4%

48.4%

48.4%

48.4%

0.5

47.5%

3.4%

6.3%

7.2%

7%

8.9%

48.4%

48.4%

48.4%

1.0

0%

1.6%

5.1%

5.7%

5.6%

5.6%

48.4%

48.4%

48.4%

2.0

0%

1%

5.2%

5%

5.4%

5.7%

13.1%

48.4%

51.6%

3.0

0%

1.2%

6.4%

5.8%

5.7%

7.4%

18%

51.6%

51.6%

10.0

0%

1.5%

7.5%

6.4%

7.7%

12.9%

26.2%

51.6%

51.6%

100.0

0%

1.5%

10.1%

12.8%

14.6%

18.3%

41.6%

51.6%

51.6%

不幸的是,没有为每个数据集找到正确的sigma的金科玉律。 可能是最好的方法之一是计算您的数据的sigma,这是√(方差),然后步步逼近该值,看看哪个sigma表现良好。由于该数据的方差在0.2和0.5之间,我们将其作为中心,并在该中心的每一侧探索几个值,以在我们的情况下看到具有高斯内核的SVM的性能。当我们观察结果表及其假预测百分比时,表明最佳性能是以非常低的西格马(0.001)和1.0及以上的校正率。 然而,如果我们在实践中使用这个模型与新数据,它可能过拟合。 这就是为什么在根据自己的训练数据测试模型时应该始终小心。更好的方法是执行交叉验证或验证未来的数据。

例二 (Polynomial Kernel)

高斯内核并不总是最好的选择,即使它是最常用的被选择的内核。 这就是为什么在这个例子中,我们将展示一个多项式内核优于高斯内核的情况。注意,即使构造了这种情况的示例数据,也可以在字段中找到类似的数据(具有更多的噪声)。 我们用于这个例子的训练数据可以在这里下载,测试数据在这里。对于示例数据,我们创建了2个具有多项式次数为3的类,并生成了测试和训练数据文件。 训练数据包含x轴上的前500个点,而测试数据包含x轴上从500到1000的点。 为了看到为什么多项式内核将工作,我们绘制数据。 左图是训练数据,右图是测试数据。

对基本代码做一下替换:

val trainingPath = "/users/.../ExampleData/SVM_Example_2.csv"

val testingPath = "/users/.../ExampleData/SVM_Example_2_Test_data.csv"

并得到以下结果:

c, s->

0.01

0.1

0.2

0.5

1.0

2.0

3.0

10.0

100.0

0.001

50%

50%

50%

50%

50%

50%

50%

50%

50%

0.01

50%

50%

50%

50%

50%

50%

50%

50%

39.8%

0.1

50%

50%

50%

50%

50%

49.4%

49.1%

47.5%

35.4%

0.2

50%

50%

50%

50%

49.4%

49.2%

48.8%

47.1%

34.3%

0.5

50%

49.9%

49.8%

49.5%

49.3%

48.9%

48.6%

46.8%

33.1%

1.0

50%

49.8%

49.7%

49.4%

49.4%

48.9%

48.6%

46.2%

50%

2.0

50%

49.8%

49.7%

49.4%

49.3%

49.2%

48.8%

45.7%

31.7%

3.0

50%

49.8%

49.7%

49.8%

49.5%

49%

48.8%

46.2%

27.4%

10.0

50%

49.8%

49.7%

49.4%

49.3%

49%

48.4%

46.7%

33.2%

100.0

50%

49.8%

49.7%

49.4%

49.3%

49.1%

48.6%

46.7%

32.2%

我们看到,即使在最好的情况下,仍有27.4%的测试数据被错误地分类。这很有趣,因为当我们看看图形时,可以在两个类之间找到一个非常清晰的区别。 我们可以微调sigma和校正率,但是当预测点非常远(x为100000)时,sigma和校正率将达到很高的水平,以达到良好的性能(时间和预测)。

修改内核:

val svm = new SVM[Array[Double]](new PolynomialKernel(2),1.0,2)

注意我们如何在PolynomialKernel的构造函数中传递2。 这2表示它试图适应的特征的程度。 如果我们不仅对于2度执行运行,而且对于2,3,4,5度执行运行,并且对于校正率再次从0.001变化到100,我们得到以下结果:

degree: 2

degree: 3

degree: 4

degree: 5

c: 0.001

49.7%

0%

49.8%

0%

c: 0.01

49.8%

0%

49.8%

0%

c: 0.1

49.8%

0%

49.8%

0%

c: 0.2

49.8%

0%

49.8%

0%

c: 0.5

49.8%

0%

50%

0%

c: 1.0

49.9%

0%

50%

0%

c: 2.0

50%

0%

47.9%

0%

c: 3.0

38.4%

0%

50%

0%

c: 10.0

49.5%

0%

49.5%

0%

c: 100.0

49.5%

0%

49.5%

0%

在这里,我们看到测试数据,其中不包含与训练数据的单个重叠点,获得100%准确度为3和5.这是一个惊人的性能相比,高斯内核与27.4%的最佳情况。 请注意,这个示例数据是构造的,因此不包含很多噪声。 这就是为什么所有“校正率”的误差率为0%的原因。 如果你增加噪声,将需要微调这种校正率。关于支持向量机的部分到此结束。

完结撒花!

原文发布于微信公众号 - 鸿的学习笔记(shujuxuexizhilu)

原文发表时间:2016-11-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码云1024

编程英语之KNN算法

1244
来自专栏程序生活

Leetcode-Easy 887. Projection Area of 3D Shapes

当时自己没有想到好办法,就是按部就班的分别求三个面的面积,注意求xy的面积的时候需要考虑grid[i][j]值是否为0

942
来自专栏zingpLiu

机器学习之线性代数

  完整内容已上传到github:https://github.com/ZingP/machine-learning/tree/master/linear_al...

1781
来自专栏PPV课数据科学社区

【学习】ggplot2绘图入门系列之二:图层控制与直方图

如前文所述,ggplot2使用图层将各种图形元素逐步添加组合,从而形成最终结果。第一层必须是原始数据层,其中data参数控制数据来源,注意数据形式...

2646
来自专栏C语言及其他语言

【编程经验】优秀题解

今天给大家带来一个我站“Manchester”大神写的一份优质题解(j解题思路很清晰):原题问题:1709: 算法7-16:弗洛伊德最短路径算法:

1141
来自专栏人工智能LeadAI

TensorFlow Tutorial-1

1、Why TensorFlow? 网上有关介绍太多了,我就不多说了,这里主要注重使用。 ? Intro.PNG ? github.PNG 2、Programi...

38411
来自专栏机器学习原理

深度学习——RNN(3)

2795
来自专栏帮你学MatLab

《Experiment with MATLAB》读书笔记(四)

读书笔记(四) 这是第四部分数组与矩阵 将代码复制到m文件即可运行 函数部分需新建m文件保存 %% 向量与矩阵 x = [2; 4] % ...

37511
来自专栏机器之心

教程 | 在Python和TensorFlow上构建Word2Vec词嵌入模型

选自adventuresinmachinelearning 机器之心编译 参与:李诗萌、刘晓坤 本文详细介绍了 word2vector 模型的模型架构,以及 T...

4687
来自专栏从流域到海域

使用Python生成一张用于登陆验证的字符图片

Python Pillow库的简单使用 使用Python生成一张用于登陆验证的字符图片, 代码使用了Pillow,Anaconda已经默认安装此库,如果你...

2099

扫码关注云+社区

领取腾讯云代金券