网络机器人吧社区

翻译||机器学习之Scikit learn

麻瓜甲studio 2019-01-20 07:18:01

原文链接:http://blog.scottlogic.com/2018/02/15/scikit-machine-learning.html


机器学习之Scikit learn


机器学习(MachineLearning, ML)是我在学习计算机科学中第一个吸引我的领域。这个概念非常直截了当,但它的应用非常强大。Google,AirBnB和 Uber 是众多大牌企业中在他们的产品中应用机器学习的。当我第一次尝试应用机器学习到我的工作中时,我发现了一个优秀的库作为学习的起始点:Scikit Learn。(链接:http://scikit-learn.org/stable/


Scikit Learn由Python发展而来,允许开发者们很容易地集成机器学习到他们自己的工程中。Spotify和Evernote是使用ScikitLearn的知名企业之二。我喜欢用Python的最新版本Python3(v3.4.6是写此篇时的最新版本)运行ScikitLearn的一个小应用。如果Python对你来说很陌生,不要害怕!我会在接下来解释每段代码的意思与目的。


Installation安装

Scikit Learn的安装是对于这次练习重要的一点。在此之前要先确保已经下载了Python 3(链接:https://www.python.org/downloads/)。用终端打开,确保你已经用pip安装了NumPy和SciPy。

 

pip install numpy

pip install scipy

 

剩下的安装步骤就很简单了。只需要一行命令就可以了:

 

pip installscikit-learn

 

经过一段时间后你会收到“successfully installed scikit-learn”提示已经安装成功。在这次练习中为了阅读CSV文件,我们还需要安装Pandas(链接:https://pandas.pydata.org/)。像之前一样,只需要一行命令:

 

pip install pandas

 

到这里我们就完成了全部的安装!


Setup  安装

Scikit Learn提供了大量的使用示例在它自己的网站(链接:http://scikit-learn.org/stable/auto_examples/index.html#examples-based-on-real-world-datasets)上,当我开始用这个库时觉得特别有用。为了在这里强调Scikit Learn,我准备实现一个分类器从有大约11000张图片的UCI数据集去分类手写体数字。这个数据集来自44个作者,每个作者要求写250个数字,而这个数据库中的每一张图片(我们称之为样本)对应于0到9之间的一个手写数字。


每个样本都表示为一个特征向量,取值范围在0到100之间。这些值表示样本中单个像素的灰度。考虑到每个样本都是在一个500×500平面像素分辨率框中编写的,这种方法将留给我们非常长的向量来处理。为了解决这个问题,我们正在考虑对图像进行重采样以减少像素数量,最后保留长度为16的特征向量。

 

这组0-9的数字在分类过程中会成为我们的分类器的类别。分类器将从30个作家(大约7500张)中抽取样本来学习每个类别的样本。剩下的样品将被保留下来测试分类器训练后的效果。每个样本都是手工分类的,这意味着我们对测试集中的每个样本都有正确的分类。这使我们能够通过比较自己的预测和我们已经掌握的分类来确定分类器的成功程度。

 

训练和测试数据集都是由UCI以CSV文件在线提供的。多亏了Pandas,将这些文件导入Python是一个简单的过程:

import pandas as pd

 

def retrieveData():

  trainingData =pd.read_csv("training-data.csv").as_matrix()

  testData =pd.read_csv("test-data.csv").as_matrix()

 

  return trainingData, testData

 

每个文件用read_csv读取后产生一个Pandas型数据框,这样就用as_matrix转换成了一个Numpy数组为了后续使用的方便。这些文件的每一行对应一个数字样本,样本由一个长度为16的特征向量组成,对应其相应的类别。分离的特征向量和类别在Scikit Learn中将被证明是有用的。

def separateFeaturesAndCategories(trainingData,testData):

  trainingFeatures = trainingData[:, :-1]

  trainingCategories = trainingData[:, -1:]

  testFeatures = testData[:, :-1]

  testCategories = testData[:, -1:]

 

  return trainingFeatures, trainingCategories,testFeatures, testCategories

 

Pre-processing 预处理

ScikitLearn提供的大部分分类器对特征尺度敏感。每个特征向量取值在0100之间,没有一致的均值方差。重新调节这些向量使其满足均值0和方差0有助于分类器在训练和分类过程中识别到任何的数字类别样本。这是机器学习流程中的一个可选步骤,但如果希望提高分类器性能这一步骤极力推荐。使用ScikitLearn的预处理包提供的standardscalar证明了实现比较简单。首先允许scaler适应训练数据学习不成比例的特征是什么样子的,然后sacler可以在训练集和测试集变换特征去保持零均值和方差:

fromsklearn.preprocessing import StandardScaler

 

defscaleData(trainingFeatures, testFeatures):

    scaler = StandardScaler()

    scaler.fit(trainingFeatures)

 

    scaledTrainingFeatures =scaler.transform(trainingFeatures)

    scaledTestFeatures =scaler.transform(testFeatures)

 

    return scaledTrainingFeatures,scaledTestFeatures

  

Classification 分类

ScikitLearn提供的大量分类器(链接:http://scikit-learn.org/stable/supervised_learning.html#supervised-learning)会满足你的需要。我决定采用随机梯度下降(StochasticGradient Descent SGD)分类器(链接:http://scikit-learn.org/stable/modules/sgd.html#classification,因为我发现自己以前用过几次。首先,我们需要将分类器与训练数据相匹配(即训练分类器)。然后我们就可以设置分类器来预测看不见的测试样本的类别。所有这一切都是ScikitLearn在短短的几行代码实现

fromsklearn.linear_model.stochastic_gradient import SGDClassifier

 

defclassifyTestSamples(trainingFeatures, trainingCategories, testFeatures):

    clf = SGDClassifier()

 

    clf.fit(trainingFeatures,trainingCategories)

    predictedCategories = clf.predict(testFeatures)

 

    return predictedCategories

 

Results 结果

我们有我们的预测结果了!现在将它们与文件上提供的类别进行比较。这里出现了几个问题:分类器有多成功?我们如何衡量它的成功?给定一个特定的度量,我们在哪里设置阈值来区分一个坏结果和一个好结果?为了回答前两个问题,我去学习了ScikitLearn的分类指标包。这个示例我选择了四个度量来实现:精Accuracy准确度(Precision、召回率RecallF1得分F1 Score

    •      Accuracy样本分类的正确度。

    •      准确度(Precision正确分配X类的样本数分配x类样本的总数的比例

    •      召回率Recall):正确分配x类的样本数正确地分配x的数量不是x类和没被分配到x的样本数之和的比例

    •      F1得分F1 Score:准确度 (P) 和召回率 (R)的一个加权平均值, Scikit Learn 中被定义为 2 * (P * R) / (P + R)

 

Scikit Learnaccuracy_score函数涵盖我们的分类器的精度。剩下的三个指标是由classification_report函数来对每个类别打印一个精度,召回率和F1得分的分析同时提供平均

fromsklearn.metrics import accuracy_score, classification_report

 

defgatherClassificationMetrics(testCategories, predictedCategories):

    accuracy = accuracy_score(testCategories,predictedCategories)

    metrics_report =classification_report(testCategories, predictedCategories)

 

    print("Accuracy rate: " +str(round(accuracy, 2)) + "\n")

    print(metrics_report)

 

分类器的运行之间的度量总是会有一个小的变化。会有一些分类器分类测试样本具有高度的确定性,而这些预测可能是一致的,但也有情况下分类器在它们的工作中缺少置信度。在这种情况下,分类器很可能在每次运行时做出不同的预测。这很可能因为训练集对特定数字的样本数量不足,或者分类器遇到与训练集显著不同的笔迹。考虑到这些变化,下面是从SGD分类器得到的一组结果

Accuracy rate: 0.84

 

             precision    recall f1-score   support

 

          0       0.98     0.84      0.90       363

          1       0.58     0.84      0.69       364

          2       0.97     0.81      0.88       364

          3       0.98     0.90      0.94       336

          4       0.95     0.93      0.94       364

          5       0.62     0.94      0.75       335

          6       1.00     0.96      0.98       336

          7       0.88     0.84      0.86       364

          8       0.85     0.76      0.80      336

          9       0.93     0.58      0.72       336

 

avg / total       0.87     0.84      0.85      3498

 

作为初次尝试,84%的准确率相当不错!这给了我第三个也是最后一个问题,“我们在哪里设置阈值来区分坏的结果和好的结果?“。这是一个很难回答的问题。这完全取决于分类器的目的,每个人认为是好的还是坏的,以及以前将机器学习应用到同一个领域任何尝试。我们能否改变我们的分类器使之始终比在这里观察到的结果更好?


Can we do better?  我们能做得更好吗?

可能的答案是:是的。有很多选择可以考虑。首先,这次练习应用了基本预处理步骤。更复杂的缩放方法可能会降低分类的敏感性甚至进一步提高指标。其次,本实例实现了一个基本的SGD分类器,没有调整ScikitLearn提供的默认参数值。我们可以修改训练数据上的迭代次数(称为历元),防止分类器在每一个历元后重新训练数据,或者多次运行分类器,使其具有热启动特性,以便分类器回忆以前的预测。


这也是值得考虑的我们只实现了ScikitLearn提供的众多分类器中的一个。虽然SGD分类器在这个例子中够用了,我们也可以考虑LinearSVCMultinomialNaive Bayes等等。这就是机器学习的乐趣所在:有太多的变量需要考虑,它们可能会改或恶化我们的结果。找到任何机器学习问题的最佳解决方案证明是一项艰巨的任务。


Conclusion  结论

以上包含了我们在ScikitLearn的练习!我们只在这里介绍了基础知识。ScikitLearn还提供了更多,而且我觉得它们很好的记录在它们自己的网站(链接:http://scikit-learn.org/stable/documentation.html。任何希望看到完整代码或者想自己尝试的人可以在GitHub(链接:https://github.com/rrhodes/scikit-learn-example看到我做的CSV文件和Python代码。祝愉快


Copyright © 网络机器人吧社区@2017