对scikit-learn的官方简介文档进行了简单的翻译,供初选者参考。
机器学习
通常说,一个机器学习问题是已知一组数据样本,试图预测出该数据的一些未知的性质。机器学习问题可以大体分为两类:
有监督学习:分类、回归
无监督学习:聚类、密度估计、降维等
加载数据
在scikit-learn中有一些标准数据集,如分类问题的iris和数字识别,回归问题的波士顿房价问题。
from sklearn import datasets
iris = datasets.load_iris()
digits = datasets.load_digits()
Dataset是一个dictionary-like 的对象,包括所有的数据和关于该数据的一些信息。数据是 .data属性,是一个(n_samples, n_features)数组。在有监督学习中,目标变量则是.target 属性。
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.]]
print(digits.target)
[0 1 2 ..., 8 9 8]
print(digits.data.shape)
print(digits.target.shape)
(1797, 64)
(1797,)
虽然原始数据可能有不同的数据结构,但.data总是一个 2D 数组 。在这个例子中,原始数据就是一个(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.]])
.data的每一行由对应图像矩阵的元素构成。
digits.data[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中,分类器是一个Python对象,具有fit(X, y)和predict(T)等方法。这里,我们使用支持向量机分类方法。
from sklearn import svm
clf = svm.SVC(gamma = 0.01, C = 100.)
为模型设定参数
gamma的值手动设为0.01, 但如果利用网格搜索和交叉验证集的方法,可能模型会有更好的性能。
将分类器命名为clf, 也就是classifier。通过向模型输入训练数据集,对模型进行学习(拟合)。
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.01, kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
Note: [:-1] 代表选出数组的除最后一项的所有数据
这样,就可以利用训练好的分类器,预测最后一个数字(不包含在输入模型的训练数据中)。
clf.predict(digits.data[-1:])
array([8])
Note: [-1:]则是选出数组的最后一个元素。
可以检查下最后一个数字是不是 8。
digits.target[-1:]
array([8])
模型保存
可以用Python的内嵌模块 pickle对scikit-learn的模型进行保存。
import pickle
s = pickle.dumps(clf)
当需用重新调用该训练好的模型时,将其从pickle中加载出来。
clf2 = pickle.loads(s)
clf2.predict(digits.data[-1:])
array([8])
在一些数据量大的情况时用joblib代替 pickle会更高效,joblib是将模型存入硬盘。
from sklearn.externals import joblib
joblib.dump(clf, 'filename.pkl')
['filename.pkl']
clf3 = joblib.load('filename.pkl')
clf3.predict(digits.data[-1:])
array([8])
一些约定
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')
回归的目标变量将被转为float64,而分类的目标变量类型会沿用。
from sklearn import datasets
from sklearn.svm import SVC
iris = datasets.load_iris()
clf = SVC()
clf.fit(iris.data, iris.target)
list(clf.predict(iris.data[:3]))
[0, 0, 0]
clf.fit(iris.data, iris.target_names[iris.target])
list(clf.predict(iris.data[:3]))
['setosa', 'setosa', 'setosa']
这里,第一个predict()返回了一个整型数组,因为iris.target是整型数组;第二个predict()返回了字符串数组,因为iris.target_names是字符串数组。
重新拟合和参数更新
分类器的Hyper-parameters可以被更新,重新调用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)
clf.predict(X_test)
array([1, 0, 1, 1, 0])
clf.set_params(kernel='rbf').fit(X, y)
clf.predict(X_test)
array([0, 0, 0, 1, 0])
这里,默认的 kernel 是rbf 首先被改为 linear,在拟合之后, 又被改回了 rbf,然后再做了预测。
多类和多标签拟合
当使用 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])
在上面的例子中,分类器是在多类的一维数组上做的拟合,其预测结果也是相应的多类一维数组。同样可以将两维数组转为标签,进行分类。
y = LabelBinarizer().fit_transform(y)
print(y)
[[1 0 0]
[1 0 0]
[0 1 0]
[0 1 0]
[0 0 1]]
classif.fit(X, y).predict(X)
array([[1, 0, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 0],
[0, 0, 0]])
这里,分类器的拟合是基于两维二进制标签y, 基于LabelBinarizer进行转化。同样,预测值亦是相同的格式。
Note: 第4和第五预测值是全零,表明未找到符合的类。
对与对标签的输出,其结果是相似的。
from sklearn.preprocessing import MultiLabelBinarizer
y = [[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]]
y = MultiLabelBinarizer().fit_transform(y)
print(y)
[[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]]
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]])