scikit-learn 机器学习简介

章节内容

在本节中,我们将介绍在scikit-learn中所使用的机器学习的基础知识点,并且给出一个简单的代码示例。

机器学习:问题设置

通常,一个机器学习问题会通过学习n个数据样本,然后去预测未知数据的属性。如果每个样本都不止一个属性,即一个多维属性(也称为多元 数据),则称其具有多个属性或特征

机器学习解决的问题可分为以下几类:

  • 监督学习,数据包含有我们要预测的额外属性(单击此处 转到scikit-learn监督学习页面)。其中包括:

    • 分类:样本属于两个或多个类别,我们想从已经标记的数据中学习如何预测未标记数据的类别。分类问题的一个例子是手写数字识别,手写数字识别的目的是将每个输入向量分配给有限的离散类别中的一个。分类问题作为一种离散的(与连续相反)监督学习形式,它有有限的类别,并且对于所提供的n个预测样本中的每个样本,尝试使用正确的类别来标记。

    • 回归:如果所期待的输出包含一个或多个连续变量,则该任务称为回归。比如根据鲑鱼的年龄和体重来预测其长度就是一个回归问题。

  • 无监督学习,无监督学习的训练数据由一组输入向量x组成,没有任何对应的目标值y。此类问题的目标是在所有数据内去发现相似数据(被称为聚类),或者确定输入空间内数据的分布(被称为 密度估计),或是为了可视化,将高维空间的数据投影到2维或3维,即降维 (单击此处 可转到Scikit-Learn无监督学习页面)。

训练集和测试集

机器学习是学习数据集的某些属性,然后针对另一个数据集来测试学到的属性的正确性。机器学习中常见做法是通过将数据集分为两部分来评估算法。我们称其中一部分为训练集,在该训练集上我们学习一些属性;我们将另一部分称为测试集,在其上面来测试学习到的属性。

加载示例数据集

scikit-learn包括一些标准数据集,例如 用于分类的 鸢尾属植物数据集手写数字识别数据集和用于回归的波士顿房价数据集

接下来,我们从shell中启动Python命令行,然后加载鸢尾属植物手写数字识别数据集。符号 $是表示shell提示,而>>>表示Python解释器提示:

    $ python
    >>> from sklearn import datasets
    >>> iris = datasets.load_iris()
    >>> digits = datasets.load_digits()

数据集是一个类似于字典结构的对象,其中包含所有数据和有关该数据的一些元数据。此数据存储在.data成员中,该成员是一个大小为[n_samples, n_features]数组。在监督问题的情况下,一个或多个标签数据存储在.target成员中。有关不同数据集的更多详细信息,请参见数据集加载部分

例如,对于手写数字识别数据集,digits.data方法可以访问用于分类的数字样本的特征:

>>> print(digits.data)
    [[ 0.   0.   5. ...   0.   0.   0.]
     [ 0.   0.   0. ...  10.   0.   0.]
     [ 0.   0.   0. ...  16.   9.   0.]
     ...
     [ 0.   0.   1. ...   6.   0.   0.]
     [ 0.   0.   2. ...  12.   0.   0.]
     [ 0.   0.  10. ...  12.   1.   0.]]

digits.target给出数字数据集的对应样本的类别,即我们尝试学习每个数字图像对应的类别:

>>> digits.target
    array([0, 1, 2, ..., 8, 9, 8])

数据数组的shape(形状)

该数据始终是2维数组(n_samples, n_features),虽然原始数据可能具有不同的形状,但对于手写数字识别数据集来说,每个样本都是8x8的图像,可以使用以下代码访问:

>>> digits.images[0]
    array([[  0.,   0.,   5.,  13.,   9.,   1.,   0.,   0.],
           [  0.,   0.,  13.,  15.,  10.,  15.,   5.,   0.],
           [  0.,   3.,  15.,   2.,   0.,  11.,   8.,   0.],
           [  0.,   4.,  12.,   0.,   0.,   8.,   8.,   0.],
           [  0.,   5.,   8.,   0.,   0.,   9.,   8.,   0.],
           [  0.,   4.,  11.,   0.,   1.,  12.,   7.,   0.],
           [  0.,   2.,  14.,   5.,  10.,  12.,   0.,   0.],
           [  0.,   0.,   6.,  13.,  10.,   0.,   0.,   0.]])

数据集上的一个简单示例说明了如何在scikit-learn上加载原始问题数据集和处理数据。

从外部数据集加载

要从外部数据集加载,请参阅加载外部数据集

学习和预测

对于手写数字识别数据集,任务是在给定图像的情况下预测其代表的数字。我们为10种可能的类别(从零到九的数字)中的每一种提供了样本,我们在其上拟合了一个 估计器(estimator),使其能够预测 还未见样本所属的类别。

在scikit-learn中,分类的一个估计器(estimator)是一个Python对象,该对象实现fit(X, y)predict(T)方法

估计器(estimator)的一个实例是类sklearn.svm.SVC,它实现支持向量机分类。估计器(estimator)的构造函数的参数作为模型的参数。

目前,我们暂且将估计器(estimator)视为黑匣子:

>>> from sklearn import svm
>>> clf = svm.SVC(gamma=0.001, C=100.)

选择模型的参数

在此示例中,我们手动设置gamma的值。要为这些参数找到合适的值,我们可以使用诸如网格搜索交叉验证之类的工具。

首先将clf(分类器)估计器实例拟合到分类模型;也就是说,它必须从模型中学习。我们通过把训练集传递给fit方法来完成学习。对于训练集来说,我们使用数据集中除了最后一个的所有图像进行训练,对最后一个图像进行预测。我们使用[:-1]Python语法来选择训练集,这将产生一个新数组,该数组包含来自digits.data除最后一项之外的所有数据:

>>> clf.fit(digits.data[:-1], digits.target[:-1])
SVC(C=100.0, gamma=0.001)

现在您可以预测新的值。在这种情况下,您对digits.data的最后一张图片进行预测。通过预测,您将确定训练集中最后一张图像最匹配的类别。

>>> clf.predict(digits.data[-1:])
array([8])

相应的图像是:

从上图可知,这是项任务极具挑战,毕竟,图像的分辨率很差。该分类器预测正确了吗(的分类结果)?

您可以运行和研究识别手写数字分类问题的完整示例: 识别手写数字

模型持久化

可以使用Python的内置持久化模型pickle在scikit-learn中保存模型:

>>> from sklearn import svm
>>> from sklearn import datasets
>>> clf = svm.SVC()
>>> X, y = datasets.load_iris(return_X_y=True)
>>> clf.fit(X, y)
SVC()
>>> import pickle
>>> s = pickle.dumps(clf)
>>> clf2 = pickle.loads(s)
>>> clf2.predict(X[0:1])
array([0])
>>> y[0]
0

pickle在大数据上效率更高,但它只能在磁盘进行pickle且不能处理字符串,所以在某些情况下,可能会使用joblib替代pickle(joblib.dumpjoblib.load):

>>> from joblib import dump, load
>>> dump(clf, 'filename.joblib') 

之后,您可以使用以下方法重新加载pickle模型(可以在另一个Python进程中):

>>> clf = load('filename.joblib') 

注意

joblib.dumpjoblib.load方法也接受类似文件的对象,而不是文件名。有关Joblib的数据持久性的更多信息,请参见此处

请注意,pickle 存在一些安全性和可维护性问题。有关scikit-learn的模型持久性的更多详细信息,请参阅模型持久性部分。

约定

scikit-learn估计器(estimator)遵循一些约束规则,以使其开发过程更具规范性。在 通用术语表和API元素中更详细地描述了这些内容。

类型转换

除非另有说明,否则输入将会被强制转换为float64:

>>> import numpy as np
>>> from sklearn import random_projection
>>> rng = np.random.RandomState(0)
>>> X = rng.rand(10, 2000)
>>> X = np.array(X, dtype='float32')
>>> X.dtype
dtype('float32')

>>> transformer = random_projection.GaussianRandomProjection()
>>> X_new = transformer.fit_transform(X)
>>> X_new.dtype
dtype('float64')

在此示例中,原本类型为float32X通过fit_transform(X)方法被强制转换为float64

回归问题的输出会被强制转换为float64,分类问题的输出维持不变:

>>> from sklearn import datasets
>>> from sklearn.svm import SVC
>>> iris = datasets.load_iris()
>>> clf = SVC()
>>> clf.fit(iris.data, iris.target)
SVC()
>>> list(clf.predict(iris.data[:3]))
[0, 0, 0]

>>> clf.fit(iris.data, iris.target_names[iris.target])
SVC()

>>> list(clf.predict(iris.data[:3]))
['setosa', 'setosa', 'setosa']

第一次调用predict()返回一个整型数组,因为训练时使用的 iris.target是一个整型数组。第二次调用predict()返回一个字符串数组,因为训练时使用的是 iris.target_names

重新训练和更新参数

通过set_params()方法可以更新估计器(estimator)的超参数。多次调用fit()方法将会覆盖以前调用fit()学习到内容:

>>> import numpy as np
>>> from sklearn.datasets import load_iris
>>> from sklearn.svm import SVC
>>> X, y = load_iris(return_X_y=True)
>>> clf = SVC()
>>> clf.set_params(kernel='linear').fit(X, y)
SVC(kernel='linear')
>>> clf.predict(X[:5])
array([0, 0, 0, 0, 0])

>>> clf.set_params(kernel='rbf').fit(X, y)
SVC()
>>> clf.predict(X[:5])
array([0, 0, 0, 0, 0])

在构造估计器(estimator)之后,默认值为rbfkernel参数首先通过 SVC.set_params()方法更改为linear,然后又把kernel参数更改回rbf来重新训练估计器(estimator)并进行第二次预测。

多类与多标签训练

在使用multiclass classifiers时,执行的训练和预测任务取决于适合的目标数据格式:

>>> from sklearn.svm import SVC
>>> from sklearn.multiclass import OneVsRestClassifier
>>> from sklearn.preprocessing import LabelBinarizer

>>> X = [[1, 2], [2, 4], [4, 5], [3, 2], [3, 1]]
>>> y = [0, 0, 1, 1, 2]

>>> classif = OneVsRestClassifier(estimator=SVC(random_state=0))
>>> classif.fit(X, y).predict(X)
array([0, 0, 1, 1, 2])

在上述情况下,分类器在多标签的一维数组下进行训练,因此predict()方法提供了相应的多标签预测。也可以在LabelBinarizer()(binary label indicators)的二维数组上进行训练:

>>> y = LabelBinarizer().fit_transform(y)
>>> classif.fit(X, y).predict(X)
array([[1, 0, 0],
       [1, 0, 0],
       [0, 1, 0],
       [0, 0, 0],
       [0, 0, 0]])

分类器是在一个2维二元数组y上 使用LabelBinarizer进行训练fit()的。在这种情况下,predict()将返回一个二维数组,该数组代表相应的多标签预测。

请注意,第四和第五个实例返回的全为零,表明它们与这三个标签都不匹配。使用多标签输出,也可以为一个实例分配多个标签:

>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> y = [[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]]
>>> y = MultiLabelBinarizer().fit_transform(y)
>>> classif.fit(X, y).predict(X)
array([[1, 1, 0, 0, 0],
       [1, 0, 1, 0, 0],
       [0, 1, 0, 1, 0],
       [1, 0, 1, 0, 0],
       [1, 0, 1, 0, 0]])

在这种情况下,分类器在每个分配了多个标签的实例上进行训练。MultiLabelBinarizer方法对2维数组进行二值化,以便进行fit。结果, predict()方法为每个实例返回带有多个预测标签的二维数组。

©2007-2019,scikit-learn开发人员(BSD许可证)。 显示此页面源码

未经允许不得转载,请联系zhouas@hotmail.com获取授权:目标检测 » scikit-learn 机器学习简介

赞 (0) 打赏

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

微信扫一扫打赏

鄂ICP备18005284号