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

Practicalexamples

在本节中,我们为您介绍一组在实际环境中的机器学习算法。 这些例子的想法是让你开始使用机器学习算法,而不深入解释底层算法。我们只专注于这些算法的特征方面,如何验证您的实现,最后尝试让您意识到常见的陷阱。

下面是可以使用的样例:

• Labeling ISP's based on their down/upload speed (K-NN)

• Classifying email as spam or ham (Naive Bayes)

• Ranking emails based on their content (Recommendation system)

• Predicting weight based on height (Linear Regression OLS)

• An attempt at rank prediction for top selling books using textregression

• Using unsupervised learning to merge features (PCA)

• Using Support Vector Machines (SVMS)

对于每个这些例子,我们使用了Smile MachineLearning库。 我们同时使用了smile-core和smile-plot库。 这些库可用于Maven,Gradle,Ivy,SBT和Leiningen。

所以在开始工作之前,我假设你在你最喜欢的IDE中创建了一个新项目,并将smile-core和smile-plot库添加到你的项目中。 使用时的额外的库,以及如何获取示例数据按照示例进行处理。

Labeling ISPs based on their down/uploadspeed (K-NN using Smile in Scala)

本节的目标是使用K-Nearest Neighbors(K-NN)算法将下载/上传速度对分类为互联网服务提供商(ISP)Alpha(由0表示)或Beta(由1表示)。 K-NN背后的想法如下:给定一组被分类的点,您可以通过查看其K个邻居(K是正整数)来对新点进行分类。这个想法是,通过检查新点与其周围点之间的欧氏距离,找到K个邻居。 对于这些邻居,然后检查最大的代表类,并将该类分配给新点。

这儿是样本数据集

第一步是先下样本数据,下面是代码:

object KNNExample {
   def main(args:Array[String]): Unit = {
    val basePath ="/.../KNN_Example_1.csv"
    val testData =getDataFromCSV(new File(basePath))
    }
  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
    valxCoordinate: Double = dataArray(0).toDouble
    valyCoordinate: Double = 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(Array(xCoordinate, yCoordinate), classifier)
  }
}

首先你可能想知道为什么是数据格式化这种方式。嗯,dataPoints和它们的标签值之间的分隔是为了能轻易地分离测试和训练数据,并且因为API预想到数据是以这种方式执行K-NN算法和绘制数据地。 其次,作为Array [Array [Double]]存储的数据点被用来支持超过2维的数据点。

给定数据,接下来要做的第一件事是看看数据是什么样子地。对于此,Smile提供了一个很好的绘图库。但为了使用这个,应用程序应该更改为Swing。此外,数据应该被反馈到绘图库以获得具有实际绘图的JPane。 更改代码后,它应该如下所示:

object KNNExample extends SimpleSwingApplication {
  def top = newMainFrame {
    title ="KNN Example"
    val basePath ="/.../KNN_Example_1.csv"
    val testData =getDataFromCSV(new File(basePath))
    val plot =ScatterPlot.plot(testData._1,
                                 testData._2, 
                                 '@', 
                                Array(Color.red, Color.blue)
                                )
   peer.setContentPane(plot)
    size = newDimension(400, 400)
  }

...

绘制数据背后的想法是验证K-NN是否是针对该特定数据集的拟合机器学习算法。 在这种情况下,数据如下:

在此图中,您可以看到,蓝色和红色点似乎在区域(3 <x <5)和(5 <y <7.5)这个区域中混合了。由于这个组是混合的,所以K-NN算法是一个好的选择,因为拟合线性决策边界将在混合区域中导致大量假分类。

考虑到使用K-NN算法是适合这个问题的选择,让我们继续实际的机器学习部分。对于此,GUI是开源的,因为它没有真正添加任何值。回忆一下机器学习的全局概念,在机器学习中有两个关键部分:预测和验证。 首先我们来看看验证,因为使用没有任何验证的模型永远不是一个好主意。 这里验证模型的主要原因是防止过拟合。然而,即使我们可以在做验证之前,也应该选择正确的K.

这个算法地缺点是没有用于找到正确的K值的黄金规则。然而,找到允许大多数数据点被正确分类的好的K可以通过查看数据来完成。另外,应该仔细挑选K以防止算法的不可判定性。 说例如K = 2,问题有2个标签,那么当一个点在两个标签之间时,算法应该选择哪一个。 有一个经验法则,K应该是特征数目的平方根(或者说,维度的数目)。在我们的例子中,K = 1,但这不是一个好主意,因为这将导致在决策边界周围地更高的假分类。 挑选K = 2将导致我们两个标签的错误,因此目前挑选K = 3似乎是一个很好的拟合。

对于这个例子,我们做2折交叉验证。 一般来说,2折交叉验证是模型验证的一个相当弱的方法,因为它将数据集拆分为一半,仅验证两次,这仍然允许过拟合,但由于数据集只有100点,10折(这是一个更强的版本)压根没有意义,因为那里只有10个数据点用于测试,这将给出一个倾斜的错误率。

def main(args: Array[String]): Unit = {
   val basePath ="/.../KNN_Example_1.csv"
    val testData =getDataFromCSV(new File(basePath))
    //Define theamount of rounds, in our case 2 and 
    //initialisethe cross validation
    val cv = newCrossValidation(testData._2.length, validationRounds)
    val testDataWithIndices = (testData
                                ._1
                                .zipWithIndex, 
                                testData
                                ._2
                                .zipWithIndex)
    val trainingDPSets= cv.train
     .map(indexList => indexList
      .map(index=> testDataWithIndices
     ._1.collectFirst { case (dp, `index`) => dp}.get))
    valtrainingClassifierSets = cv.train
     .map(indexList => indexList
      .map(index=> testDataWithIndices
     ._2.collectFirst { case (dp, `index`) => dp}.get))
    valtestingDPSets = cv.test
     .map(indexList => indexList
      .map(index=> testDataWithIndices
     ._1.collectFirst { case (dp, `index`) => dp}.get))
    val testingClassifierSets= cv.test
     .map(indexList => indexList
      .map(index=> testDataWithIndices
     ._2.collectFirst { case (dp, `index`) => dp}.get))
    valvalidationRoundRecords = trainingDPSets
     .zipWithIndex.map(x => ( x._1,           
                                trainingClassifierSets(x._2),
                               testingDPSets(x._2),
                               testingClassifierSets(x._2)
                               )
                       )
   validationRoundRecords
        .foreach {record =>
      val knn =KNN.learn(record._1, record._2, 3)
      //And foreach test data point make a prediction with the model
      valpredictions = record
        ._3
        .map(x=> knn.predict(x))
       .zipWithIndex
      //Finallyevaluate the predictions as correct or incorrect
      //and countthe amount of wrongly classified data points.
      val error =predictions
        .map(x=> if (x._1 != record._4(x._2)) 1 else 0)
        .sum
     println("False prediction rate: " + error / predictions.length* 100 + "%")
    }
  }

如果你执行这个代码几次,你可能会注意到错误的预测率波动相当多。这是由于用于训练和测试的随机样本。 当这个随机采样有些不幸时,错误率变得更高,而当获取好的随机采样时,错误率可能非常低。

不幸的是,我不能为你提供一个黄金规则,即使你的模型有着最好的训练集去训练。有人会说,具有最小错误率的模型总是最好的,但是当你回想起过拟合这一术语时,选择这个特定的模型可能对未来的数据执行真的很糟糕。 这就是为什么有一个足够大和代表性的数据集是一个良好的机器学习应用程序的关键。然而,当意识到这个问题,你可以不断根据新的数据和已知正确的分类不断更新你的模型。

让我们回顾一下我们迄今为止做了什么。首先,你得到了训练和测试数据。 接下来你生成和验证几个模型,并选择给出最好的结果的模型。 然后我们现在有一个最后一步要做,这是使用这个模型进行预测:

val knn = KNN.learn(record._1, record._2, 3)
val unknownDataPoint = Array(5.3, 4.3)
val result = knn.predict(unknownDatapoint)
if (result == 0)
{
   println("Internet Service Provider Alpha")
}
else if (result == 1)
{
   println("Internet Service Provider Beta")
}
else
{
   println("Unexpected prediction")
}

执行此代码的结果是将unknownDataPoint(5.3,4.3)标记为ISP Alpha。 这是更容易分类的点之一,因为它清楚地在图中的数据点的 Alpha字段中。 因为现在很清楚如何做这些预测,我不会介绍给你其他点,但随时可以尝试不同的点去进行预测。

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

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

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏京东技术

【解题报告】看雪·京东2018CTF—京东AI CTF大挑战特别题

近日,京东安全联合安全界的黄埔军校看雪论坛举办了一次线上CTF大赛,近3w人参赛。参与解答“京东AI CTF大挑战特别题”的同学有1435人,最终解出题目的只有...

1512
来自专栏风口上的猪的文章

机器学习(2) - KNN识别MNIST

 https://github.com/s055523/MNISTTensorFlowSharp

2172
来自专栏北京马哥教育

Python数据分析、挖掘常用工具

? 作者:深度沉迷学习 Python爱好者社区专栏作者 简书地址:https://www.jianshu.com/u/d76c6535dbc5 Python...

6448
来自专栏SeanCheney的专栏

Numpy和MatplotlibPython科学计算——Numpy线性代数模块(linalg)随机模块(random)Python的可视化包 – Matplotlib2D图表3D图表图像显示

Python科学计算——Numpy Numpy(Numerical Python extensions)是一个第三方的Python包,用于科学计算。这个库的前身...

6094
来自专栏机器学习之旅

基于Tensorflow实现DeepFM前言网络结构代码部分

DeepFM,Ctr预估中的大杀器,哈工大与华为诺亚方舟实验室荣耀出品,算法工程师面试高频考题,有效的结合了神经网络与因子分解机在特征学习中的优点:同时提取到低...

2314
来自专栏码云1024

游戏中的人物是如何寻路的?

50013
来自专栏AI研习社

TensorFlow 中 RNN 实现的正确打开方式

上周写的文章《完全图解 RNN、RNN 变体、Seq2Seq、Attention 机制》介绍了一下 RNN 的几种结构,今天就来聊一聊如何在 TensorFlo...

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

使用R语言进行异常检测

本文结合R语言,展示了异常检测的案例,主要内容如下: (1)单变量的异常检测 (2)使用LOF(local outlier factor,局部异常因子)进行异常...

3806
来自专栏一心无二用,本人只专注于基础图像算法的实现与优化。

肤色检测算法 - 基于二次多项式混合模型的肤色检测。

   由于能力有限,算法层面的东西自己去创新的很少,很多都是从现有的论文中学习,然后实践的。       本文涉及的很多算法,在网络上也有不少同类型的文章,但是...

28611
来自专栏码云1024

游戏中的人物为什么不迷路?

本文章并非面向零基础的人,而是面对黄金段位的 LOL 大神。本文同样适合出门在外没有导航,就找不到家的孩子。

77529

扫码关注云+社区

领取腾讯云代金券