scikit-learn 学习(一)介绍与安装

现在开始学习 scikit-learn 库。直接从学习官方文档入手,打算边翻译边码代码。

1. 安装

pip 安装

pip install -U scikit-learn

2. 介绍

2. 1 加载一个样例数据集

1
2
3
from sklearn import datasets
iris = datasets.load_iris()
digits = datasets.load_digits()

一个数据集类似字典,存储所有数据和一些相关数据。数据存储在 .data 成员中。是 n_samples, n_features 维的数组。监督学习中的响应变量存储在 .target 中。例如,digits.data给出了数字样例的特征。digits 数据集给出了手写字体数据,每一个数字代表写字过程中的压力.

1
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 给出了真实的数字, 他是我们想要学习的数字图像的响应变量.

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

数据集的维度:
虽然原始数据可能有不同维数,但我们总是将数据处理为2维数组, 维数为(n_samples, n_features). 在 digits 中,每一个样本都是(8, 8)的图像,可以通过如下获得

1
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.]])

通过如下代码可见,每一个样本,即数据集中每一行都是将一个数字图像矩阵拉直成向量的结果

1
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.])

2.2 学习和预测

给出10个类别的样本,从数字0到9,我们拟合一个 estimator 来预测类别.

在 sclkit-learn 中,一个 estimator 是一个 Python 对象,并有方法 fit(X, y)predict(T).

一个 estimator 例子是类 sklean.svm.SVC ,它实现了支持向量分类(support vector classification).

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

选择模型参数:
在这里我们手动设置 gamma 值.通过使用 grid search 与交叉验证可能会自动找到好的参数.gamma 越大,RBF核函数的高斯分布方差越小,峰越窄.C 是惩罚因子.

这里我们把 estimator 实例称为 clf 表示它是一个 classifier.现在拟合模型.

1
clf.fit(digits.data[:-1], digits.target[:-1])
SVC(C=100.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma=0.001, kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)

现在预测最后一个我们没有训练的数据

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

真实图像如下所示

(真没看出来)

2.3 模型持久化

通过使用Python内置的持久化模块–pickle,可以在scikit中存储模型.

1
2
3
4
5
6
from sklearn import svm
from sklearn import datasets
clf = svm.SVC()
iris = datasets.load_iris()
X, y = iris.data, iris.target
clf.fit(X[1:], y[1:])
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)
1
2
3
4
import pickle
s = pickle.dumps(clf)
clf2 = pickle.loads(s)
clf2.predict(X[0:1])
array([0])
1
y[0]
0

在具体情形下,可能使用 joblib 代替 pickle。它在大数据上更有效,但是只能从磁盘中读取。

1
2
from sklearn.externals import joblib
joblib.dump(clf, 'filename.pkl')
['filename.pkl']
1
clf = joblib.load('filename.pkl')

2.4 约定

scikit-learn estimators 遵循一些规则

  • 类型转换
    :除非特别指定,输入将被转换成 float64
1
2
3
4
5
6
7
import numpy as np
from sklearn import random_projection

rng = np.random.RandomState(0) # 随机数种子
X = rng.rand(10, 2000) # 10*2000的 0~1的随机数
X = np.array(X, dtype='float32')
X.dtype
dtype('float32')
1
2
3
transformer = random_projection.GaussianRandomProjection()
X_new = transformer.fit_transform(X)
X_new.dtype
dtype('float64')

这里,Xfloat32,通过fit_tranform(X)'转换到float64.

回归的 targets 被转换为 float64,分类的 targets 保持不变:

1
2
3
4
5
from sklearn import datasets
from sklearn.svm import SVC
iris = datasets.load_iris()
clf = SVC()
clf.fit(iris.data[3:], iris.target[3:])
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)
1
list(clf.predict(iris.data[:3]))
[0, 0, 0]
1
clf.fit(iris.data[3:], iris.target_names[iris.target[3:]])
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)
1
list(clf.predict(iris.data[:3]))
['setosa', 'setosa', 'setosa']
1
iris.target_names[iris.target[:3]]
array(['setosa', 'setosa', 'setosa'],
      dtype='<U10')

这里第一个 predict() 返回整数数组因为拟合的是iris.target,第二个predict()返回字符串数组因为拟合的是iris.target_names

  • 再拟合并更新参数

estimator 的超参数可以在建立后通过 sklearn.pipeline.Pipeline.set_params方法更新。重复使用fit()会覆盖之前学习的参数。

1
2
3
4
5
6
7
8
9
10
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='ovr', degree=3, gamma='auto', kernel='linear',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)
1
clf.predict(X_test)
array([1, 0, 1, 1, 0])
1
clf.set_params(kernel='rbf').fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
  decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
  max_iter=-1, probability=False, random_state=None, shrinking=True,
  tol=0.001, verbose=False)
1
clf.predict(X_test)
array([0, 0, 0, 1, 0])

这里默认的核函数 rbf 首先转换成了 linear,再转换回去。

  • 多分类和多标签拟合

当使用多分类器,学习预测任务的表现依赖于 target 数据的格式

1
2
3
4
5
6
7
8
9
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 方法提供了相应的预测。它也可以拟合二维标签数值化的2维数组

1
2
3
y = LabelBinarizer().fit_transform(y) # 用二进制表示
print(y)
classif.fit(X, y).predict(X)
[[1 0 0]
 [1 0 0]
 [0 1 0]
 [0 1 0]
 [0 0 1]]





array([[1, 0, 0],
       [1, 0, 0],
       [0, 1, 0],
       [0, 0, 0],
       [0, 0, 0]])

注意到第四个和第五个实例返回的都是0,这表明没有和标签拟合。对于多标签的输出,类似的

1
2
3
4
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]])
分享到