章节内容
在本节中,我们介绍我们在scikit-learn中使用的机器学习词汇,并给出一个简单的学习示例。
机器学习:问题设置
一般来说,学习问题考虑一组n个数据样本,然后尝试预测未知数据的属性。 如果每个样本多于单个数字,并且例如多维条目(也称为多变量数据),则称其具有若干属性或特征。
我们可以在几个大类中分离学习问题:
- 监督学习,其中数据带有我们想要预测的附加属性(点击这里进入scikit-learn监督学习页面)。这个问题可以是:
- 分类:样本属于两个或更多类,我们想从已经标记的数据学习如何预测未标记数据的类。 分类问题的示例将是手写数字识别示例,其中目的是将每个输
入向量分配给有限数量的离散类别中的一个。 考虑分类的另一种方式是作为监督学习的离散(而不是连续)形式,其中此时具有有限数量的类别,并且
对于所提供的n个样本中的每一个,我们需要做的是尝试用正确的类别或类别来标记它们 。
- 回归:如果期望的输出由一个或多个连续变量组成,则任务称为回归。 回归问题的一个例子是鲑鱼的长度作为其年龄和体重的函数的预测。
- 无监督学习,其中训练数据由一组没有任何相应目标值的输入向量x组成。 这样的问题的目标可以是在数据内发现相似示例的组,其被称为聚类,或者确定在输
入空间内的数据的分布,称为密度估计,或者从高维 空间下降到二维或三维,以便可视化(单击此处转到Scikit-Learn无监督学习页面)。
训练集和测试集
机器学习是关于学习数据集的一些属性并将它们应用到新数据。 这就是为什么在机器学习中评估算法的常见做法是将手头的数据分成两组,一组我们称为训练集,
我们在其上学习数据属性,一组我们称为测试集,我们测试这些组属性。
加载示例数据集
scikit-learn附带了一些标准数据集,例如用于分类的莺尾花数据集(iris)和数字数据集(digits)以及用于回归的波士顿房价数据集。
在下面,我们从shell中启动一个Python解释器,然后加载iris和digits数据集。 我们的符号约定是$表示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])
数据数组的形状
数据始终是2D数组,形状(n_samples,n_features),尽管原始数据可能具有不同的形状。 在数字的情况下,每个原始样本是形状(8,8)的图像,并且可以使用以下访问:
>>> 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个可能的类(数字0到9)中的每一个的样本,其中我们拟合估计器以能够预测未看见的样本所属的类。
在scikit-learn中,分类的估计器是实现方法 fit(X, y)
和predict(T)的Python对象。
估计器的一个示例是实现支持向量分类的类 sklearn.svm.SVC
。 估计器的构造函数使用模型的参数作为参数,但暂时,我们将把估计器视为一个黑盒:
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, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma=0.001, kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
现在你可以预测新的数值了。我们可以让这个训练器告诉我们 digits
数据集我们没有作为训练数据使用的最后一张图像是什么数字。
clf.predict(digits.data[-1:])
array([8])
相应的图片如下图:
![](https://img-blog.csdn.net/20170222190652296)
如你所见,这是一个具有挑战性的任务:图像的分辨率差。 你同意分类器吗?
这个分类问题的一个完整例子是可以运行和学习的示例:识别手写数字。
模型持久性
可以使用Python的内置持久性模型(即pickle)在scikit中保存模型:
>>> from sklearn import svm
>>> from sklearn import datasets
>>> clf = svm.SVC()
>>> iris = datasets.load_iris()
>>> X, y = iris.data, iris.target
>>> clf.fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> import pickle
>>> s = pickle.dumps(clf)
>>> clf2 = pickle.loads(s)
>>> clf2.predict(X[0:1])
array([0])
>>> y[0]
0
对于scikit,也许使用joblib的pickle替代——(joblib.dump
& joblib.load
)更有趣。因为它在处理带数据时更高效。但是遗憾的是它只能把数据持久化到硬盘而不是一个字符串(译注:搬到string字符串意味着数据在内存中):
from sklearn.externals import joblib
>>> joblib.dump(clf, 'filename.pkl')
往后你就可以加载这个转储的模型(也能在另一个Python进程中使用),如下:
clf = joblib.load('filename.pkl')
注意
:
joblib.dump返回一个文件名的列表,每一个numpy数组元素包含一个clf在文件系统上的名字,在用joblib.load加载的时候所有的文件需要在相同的文件夹下
注意pickle有一些安全和可维护方面的问题。请参考Model persistent 获得在scikit-learn中模型持久化的细节。
惯例约定
scikit-learn的各种拟合(评估)函数遵循一些确定的规则以使得他们的用法能够被预想到(译:使得各种学习方法的用法统一起来)
类型转换
除非特别指定,输入将被转换为 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')
在这个例子中,X是float32,被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(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> list(clf.predict(iris.data[:3]))
[0, 0, 0]
>>> clf.fit(iris.data, iris.target_names[iris.target])
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> list(clf.predict(iris.data[:3]))
['setosa', 'setosa', 'setosa']
这里第一个predict()返回一个整数数组,是因为iris.target(一个整数数组)被用于拟合。第二个predict()返回一个字符串数组,因为iris.target_names被用于拟合
重拟合和更新参数
一个拟合(评估)函数的混合参数(超参数)能够在通过sklearn.pipeline.Pipeline.set_params方法构造之后被更新。多次调用fit()能够覆写之前fit()学习的内容:
>>> import numpy as np
>>> from sklearn.svm import SVC
>>> rng = np.random.RandomState(0)
>>> X = rng.rand(100, 10)
>>> y = rng.binomial(1, 0.5, 100)
>>> X_test = rng.rand(5, 10)
>>> clf = SVC()
>>> clf.set_params(kernel='linear').fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='linear',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> clf.predict(X_test)
array([1, 0, 1, 1, 0])
>>> clf.set_params(kernel='rbf').fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> clf.predict(X_test)
array([0, 0, 0, 1, 0])
这里,用SVC()构造之后,开始拟合(评估)函数默认的'rbf'核被改编成'linear',后来又改回'rbf'去重拟合做第二次的预测。
多类与多标签拟合
当使用多类与多分类器时,执行的学习和预测任务取决于适合的目标数据的格式:
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])
在上述情况下,分类器适合于多类标签的1d阵列,并且
predict()方法因此提供对应的多类别预测。 它也可以适合二进制标签指示器的二维阵列:
>>> 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]])
这里,使用
LabelBinarizer,分类器是
y的二进制标签表示上的
fit()。 在这种情况下,
predict()返回一个代表相应的multilabel预测的2d数组。
请注意,第四个和第五个实例返回全零,表示它们与三个标签都不fit。 使用multilabel输出,同样可以为一个实例分配多个标签:
>> from sklearn.preprocessing import MultiLabelBinarizer
>> y = [[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]]
>> y = preprocessing.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, 1, 0],
[0, 0, 1, 0, 1]])
在这种情况下,分类器适合于每个分配了多个标签的实例。
MultiLabelBinarizer用于二进制化2d多阵列阵列以
fit。 因此,
predict()返回一个2d数组,每个实例有多个预测标签。