文章整体结构借鉴An introduction to machine learning with scikit-learn。
1. 加载示例数据集
scikit-learn
内置了一些常用的标准数据集,如用于分类的iris
与digits
数据集以及用于回归的波士顿房价
数据集。
下面演示如何分别加载iris
和digits
数据集,在终端中输入python
进入python
解释器环境后,输入以下命令:
from sklearn import datasets
iris = datasets.load_iris()
digits = datasets.load_digits()
若以上命令正确执行,则说明数据加载完成。在scikit-learn
中,数据集是一个类似字典的对象,训练特征存储在成员.data
中,而目标(真实值)存储在成员.target
中,关于数据集的详细信息可参考这里。
以digits
数据集为例:
print digits.data
print digits.target
2. 学习与预测
digits
数据集的任务是给定一个图像预测该图像所代表的数字。显然该问题是一个多分类问题(10类,数字0~9),即每个样本的预测结果有10种可能性。而我们需要做的是生成一个分类器,确定样本到底属于哪个类别。
在scikit-learn
中,分类器(estimator
)是一个Python
对象,该对象实现了fit(X, y)
和 predict(T)
方法,其中方法fit(X, y)
是通过训练样本[X, y]
对模型进行训练,而方法predict(T)
是对测试样本T
进行预测。
训练样本:用于模型的训练,其主要包含两个部分,一个是特征,另一个是真实值。
测试样本:用于模型性能测试,其是“隐藏”了真实值的训练样本
。
假若采用的分类模型为SVM
,代码如下所示:
from sklearn import svm
clf = svm.SVC(gamma=0.001, C=100.) # 初始化分类器
clf.fit(digits.data[:-1], digits.target[:-1]) # 模型训练
clf.predict(digits.data[-1:]) # 预测
gamma
和C
是SVM
模型的参数,又称超参(hyper-parameter
),为了简单起见,此处手动进行设定。而在实际模型训练过程中,调参的步骤十分重要,仅次于特征工程。
digits.data[:-1]
是指去除digits
数据集中的最后一个特征样本,同理,digits.target[:-1]
是指去除digits
数据集中的最后一个特征样本对应的真实值,而digits.data[-1:]
是指选取digits
数据集中的最后一个特征样本,其对应的图形如下所示。

图 1 测试样本图像
执行以上代码后,终端输出:array([8])
,即模型对该测试样本的预测结果为8,而该样本的真实值也为8(可在终端输入digits.target[-1:]
进行查看),说明模型预测正确。
3. 模型持久化
模型持久化
主要用于提高模型的可复用性。当样本数据量很大的时候,训练一个模型是相当耗时的,而退出终端时,加载在内存中的模型也随之释放。为了避免这种情况,通常将训练好的模型持久化到磁盘,待需要使用该模型时,只需要将其从磁盘直接加载到内存,而无需重新训练。
实现模型持久化
有两种方法:一种是使用Python
内置的pickle
模块;另一种是使用scikit-learn
的joblib
模块,该模块在大数据集上比pickle
模块效率要高。
# 使用pickle模块
import pickle
s = pickle.dumps(clf)
clf_renew = pickle.loads(s)
# 使用joblib模块
from sklearn.externals import joblib
joblib.dump(clf, 'filename.pkl')
clf_renew = joblib.load('filename.pkl')
关于模型持久化
的更多详细信息参见这里。
4. 惯例
在scikit-learn
中,为了使estimator
具有更好的预测性能,有一些tricks需要遵循。
类型转换
默认情况下,输入数据会被自动转换为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)
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']
参数更新
通过方法sklearn.pipeline.Pipeline.set_params可对estimator
的超参进行更新。
>>> 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])