机器学习:问题设置
一般的,一个学习问题考虑一个n个样本集合的数据,然后尝试预测未知数据的属性。如果每个样本都超过一个数,比如是多维度条目。被叫做有多个特征或者属性。
我们可以把学习问题分成几个大类:
·监督学习,数据有我们要预测的额外的属性。问题可以是:
·分类:样本属于两个或更多的类别,我们要从已经标记过的数据学习如果预测未分类数据的类别。一个分类的例子是手写数字识别,目标是给每个输入向量分配一个分类的数字。
·回归:如果期望的输出包含一个或多个连续变量,任务就被叫做回归,一个回归的例子是根据鲑鱼的年龄和重量预测它的长度。
·无监督学习,训练数据不包括任何对应目标值得输入向量x 的集合组成。这种问题的目标是发现数据里的相似数据的分组,这被叫做聚类。或者是在输入空间里决定数据的分布,被叫做密度估计。或者从一个高纬度空间投射数据到2维或者3维空以显示
训练集合和测试集合
机器学习是关于学习数据集的一些属性,并应用到其他数据上。这就是为什么机器学习里通常评估算法的方式是把手里的数据拆分成两个集合,一个我们叫做训练集,用来学习数据的属性,另一个叫做测试集,我们用来测试这些属性。
加载一个数据集
scikit-learn自带一些标准数据集,比如iris和digits数据集用来做分类,boston house prices dataset用来做回归。
下面我们启动一个python解释器,并加载iris和digits数据集。
$ python
>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> digits = datasets.load_digits()
一个数据集是一个字典类的对象,里面有所有的数据还有关于数据的元数据。这些数据存在.data成员里,是n_samples,k n_features 数组,在监督学习问题里,一个或多个相应变量存在.target成员里。
例如,对于digits数据集,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数组,虽然原始数据可能有不同的形状,在这个数字的例子里,每个原始样本都是一个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.]])
学习和预测
在数字数据集的例子里,任务是预测,给定一个图像,它表示的数字是啥,我们给10个可能的类别(0到9)每个一些样本来让我们适配估计量,使之有能力预测未来的样本的类别。
在scikit-learn里,分类的估计量是一个Python对象,实现了fit(X, y)和predict(T)方法。
估计量的一个例子是sklearn.svm.SVC。实现了支持向量分类。估计量构造函数把模型的参数作为参数
>>> from sklearn import svm
>>> clf = svm.SVC(gamma=0.001, C=100.)
选择模型参数
我们手动设置gamma的值,如果用类似于grid search或者cross validation这样的工具可以自动找到好的值。
我们把估计量实例叫clf,因为它是一个分类器,它现在必须适合模型,也就是说必须从模型学习。这个通过给fit方法传我们的训练数据实现。作为训练集合,让我们使用数据集合里除了最后一个的其他所有图像。我们使用Python的[:-1]语法,产生一个新的数组,包含除了最后一个之外的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)
现在你可以预测新值了,我们可以问分类器最后一张图像里的数字是什么
>>>clf.predict(digits.data[-1:])
array([8])
模型持久化
可以用Python内置的持久化模块pickle来保存模型:
>>> 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)。在大数据上更有效,但是只能保存到磁盘上,而不能到字符串。
>>> from sklearn.externals import joblib
>>> joblib.dump(clf, 'filename.pkl')
之后你可以把pickle了的模型加载回来。
>>>clf=joblib.load('filename.pkl')
注意:joblib.dump返回一个文件列表。clf对象里包含的每个单独的numpy数组被串行化到文件系统的单独文件里。当joblib.load加载模型的时候所有文件都需要在同一个目录里。
惯例
scikit-learn 估计量遵循下属原则以使其行为更可预测。
type casting
除非另外指明,否则输入会被转换到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']
这里,由于iris.target(整数数组)被fit使用,第一个predict()返回了整数数组,第二个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])
这里,默认核rbf在通过SVC()构造后被改变为linear,然后变回rbf来重新适应估计量。