3.6. scikit-learn:Python中的机器学习

作者Fabian Pedregosa,Gael Varoquaux

../../_images/scikit-learn-logo.png

先决条件

3.6.1. 加载示例数据集

Photo of Iris Virginia

首先,我们将加载一些数据来玩。我们将使用的数据是一个非常简单的花数据库,称为Iris数据集。

我们有150个鸢尾花的观测样本,指定一些测量:萼片长度,萼片宽度,花瓣长度和花瓣宽度及其子类型:Iris setosaIris versicolorIris virginica

要将数据集加载到Python对象中:

>>> from sklearn import datasets
>>> iris = datasets.load_iris()

此数据存储在.data成员中,它是一个(n_samples, n_features)数组。

>>> iris.data.shape
(150, 4)

每个观察的类存储在数据集的.target属性中。这是长度为n_samples的整数1D数组:

>>> iris.target.shape
(150,)
>>> import numpy as np
>>> np.unique(iris.target)
array([0, 1, 2])

重整数据的示例:数字数据集

../../_images/digits_first_image.png

数字数据集由1797个图像组成,其中每个图像是表示手写数字的8x8像素图像:

>>> digits = datasets.load_digits()
>>> digits.images.shape
(1797, 8, 8)
>>> import pylab as pl
>>> pl.imshow(digits.images[0], cmap=pl.cm.gray_r)
<matplotlib.image.AxesImage object at ...>

要将这个数据集与scikit一起使用,我们将每个8x8图像转换为长度为64的向量:

>>> data = digits.images.reshape((digits.images.shape[0], -1))

3.6.1.1. 学习和预测

现在我们有了一些数据,我们想从中学习并预测新数据。scikit-learn中,我们通过创建estimator并调用其fit(X, Y) 方法。

>>> from sklearn import svm
>>> clf = svm.LinearSVC()
>>> clf.fit(iris.data, iris.target) # learn from the data
LinearSVC(...)

一旦我们从数据中学习,我们可以使用我们的模型来预测未知数据的最可能的结果:

>>> clf.predict([[ 5.0,  3.6,  1.3,  0.25]])
array([0])

注意

我们可以通过以下划线结尾的属性访问模型的参数:

>>> clf.coef_   
array([[ 0...]])

3.6.2. 分类

3.6.2.1. k-最近邻分类器

最简单的可能的分类器是最近的邻居:给定新的观察值,在n维空间中取最接近它的训练样本的标签,其中n 特征

../../_images/iris_knn.png

k-最近邻分类器在内部使用基于球树的算法来表示其训练的样本。

KNN(k-nearest neighbors)分类示例

>>> # Create and fit a nearest-neighbor classifier
>>> from sklearn import neighbors
>>> knn = neighbors.KNeighborsClassifier()
>>> knn.fit(iris.data, iris.target)
KNeighborsClassifier(...)
>>> knn.predict([[0.1, 0.2, 0.3, 0.4]])
array([0])

训练集和测试集

当试验学习算法时,重要的是不要测试用于拟合估计量的数据的估计量的预测。事实上,使用kNN估计器,我们将始终在训练集上获得完美的预测。

>>> perm = np.random.permutation(iris.target.size)
>>> iris.data = iris.data[perm]
>>> iris.target = iris.target[perm]
>>> knn.fit(iris.data[:100], iris.target[:100])
KNeighborsClassifier(...)
>>> knn.score(iris.data[100:], iris.target[100:])
0.95999...

奖金问题:为什么我们使用随机排列?

3.6.2.2. 支持向量机(SVM)进行分类

3.6.2.2.1. Linear Support Vector Machines

SVM试图构建一个超平面,最大化两个类之间的余量。它选择输入的一个子集,称为支持向量,它是最接近分离超平面的观察值。

../../_images/svm_margin.png
>>> from sklearn import svm
>>> svc = svm.SVC(kernel='linear')
>>> svc.fit(iris.data, iris.target)
SVC(...)

scikit-learn中有几个支持向量机实现。最常用的是svm.SVCsvm.NuSVCsvm.LinearSVC; “SVC”代表支持向量分类器(还存在用于回归的SVM,在scikit-learn中称为“SVR”)。

练习

在数字数据集上训练svm.SVC留出最后10%,并测试这些观察的预测性能。

3.6.2.2.2. Using kernels

类不总是可以通过超平面分离,因此期望具有不是线性的但可以是例如多项式或指数的决策函数:

线性内核 多项式核 RBF核心(径向基函数)
>>> svc = svm.SVC(kernel='linear')
>>> svc = svm.SVC(kernel='poly',
... degree=3)
>>> # degree: polynomial degree
>>> svc = svm.SVC(kernel='rbf')
>>> # gamma: inverse of size of
>>> # radial kernel

练习

上面提到的哪些内核在数字数据集上有更好的预测性能?

3.6.3. 聚类:将观察结果分组在一起

给定虹膜数据集,如果我们知道有三种类型的虹膜,但没有访问它们的标签,我们可以尝试无监督学习:我们可以聚类观察通过一些标准分为几组。

3.6.3.1. K-means聚类

最简单的聚类算法是k均值。这将集合分成k个集群,将每个观察分配给集群,以便将该观察(在n t>维空间中)的距离与集群的平均值最小化;然后重新计算均值。此操作迭代运行,直到群集收敛,最大值为max_iter轮次。

(在SciPy的cluster包中可以使用k-means的另一种实现方式。scikit-learn实现与提供对象API和几个附加功能(包括智能初始化)不同。)

>>> from sklearn import cluster, datasets
>>> iris = datasets.load_iris()
>>> k_means = cluster.KMeans(n_clusters=3)
>>> k_means.fit(iris.data)
KMeans(...)
>>> print(k_means.labels_[::10])
[1 1 1 1 1 0 0 0 0 0 2 2 2 2 2]
>>> print(iris.target[::10])
[0 0 0 0 0 1 1 1 1 1 2 2 2 2 2]
地面实况 K-均值(3簇) K-均值(8簇)

图像压缩应用

聚类可以被看作是从观察结果中选择少量信息的一种方式(如在较小空间上的投影)。例如,这可以用于后置图像(将色调的连续渐变转换为较少色调的几个区域):

>>> from scipy import misc
>>> face = misc.face(gray=True).astype(np.float32)
>>> X = face.reshape((-1, 1)) # We need an (n_sample, n_feature) array
>>> K = k_means = cluster.KMeans(n_clusters=5) # 5 clusters
>>> k_means.fit(X)
KMeans(...)
>>> values = k_means.cluster_centers_.squeeze()
>>> labels = k_means.labels_
>>> face_compressed = np.choose(labels, values)
>>> face_compressed.shape = face.shape
原始图像 K均值量化(K = 5)

3.6.4. 主成分分析减少尺寸

pca_3d_axis pca_3d_aligned

上述观察所跨越的点云在一个方向上是非常平坦的,使得一个特征几乎可以使用2其他特征来精确计算。PCA找到数据不是flat的方向,它可以通过在子空间上投影来降低数据的维度。

警告

根据您的scikit-learn版本,PCA将在模块decompositionpca中。

>>> from sklearn import decomposition
>>> pca = decomposition.PCA(n_components=2)
>>> pca.fit(iris.data)
PCA(copy=True, n_components=2, whiten=False)
>>> X = pca.transform(iris.data)

现在我们可以可视化(转换)虹膜数据集:

>>> import pylab as pl
>>> pl.scatter(X[:, 0], X[:, 1], c=iris.target)
<matplotlib.collections...Collection object at ...>
../../_images/pca_iris.png

PCA不仅可用于高维数据集的可视化。它还可以用作预处理步骤,以帮助加快对高维度无效的监督方法。

3.6.5. 把它放在一起:面部识别

一个显示面部识别的示例,使用主成分分析来降维,并使用支持向量机进行分类。

../../_images/faces1.png

面部识别示例的精简版

import numpy as np
import pylab as pl
from sklearn import cross_val, datasets, decomposition, svm
# ..
# .. load data ..
lfw_people = datasets.fetch_lfw_people(min_faces_per_person=70, resize=0.4)
perm = np.random.permutation(lfw_people.target.size)
lfw_people.data = lfw_people.data[perm]
lfw_people.target = lfw_people.target[perm]
faces = np.reshape(lfw_people.data, (lfw_people.target.shape[0], -1))
train, test = iter(cross_val.StratifiedKFold(lfw_people.target, k=4)).next()
X_train, X_test = faces[train], faces[test]
y_train, y_test = lfw_people.target[train], lfw_people.target[test]
# ..
# .. dimension reduction ..
pca = decomposition.RandomizedPCA(n_components=150, whiten=True)
pca.fit(X_train)
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
# ..
# .. classification ..
clf = svm.SVC(C=5., gamma=0.001)
clf.fit(X_train_pca, y_train)
# ..
# .. predict on new images ..
for i in range(10):
print(lfw_people.target_names[clf.predict(X_test_pca[i])[0]])
_ = pl.imshow(X_test[i].reshape(50, 37), cmap=pl.cm.gray)
_ = raw_input()

完整代码:faces.py

3.6.6. 线性模型:从回归到稀疏

糖尿病数据集

糖尿病数据集包括442个患者的10个生理变量(年龄,性别,体重,血压)测量,以及一年后疾病进展的指示:

>>> diabetes = datasets.load_diabetes()
>>> diabetes_X_train = diabetes.data[:-20]
>>> diabetes_X_test = diabetes.data[-20:]
>>> diabetes_y_train = diabetes.target[:-20]
>>> diabetes_y_test = diabetes.target[-20:]

手头的任务是从生理变量预测疾病预测。

3.6.6.1. 稀疏模型

为了改善问题的调节(无意义的变量,减轻维度的诅se,作为特征选择预处理等等)。),有趣的是仅选择信息特征并将非信息特征设置为0。这种称为Lasso的惩罚方法可以将一些系数设置为零。这样的方法被称为稀疏方法,稀疏性可以被看作是奥卡姆剃刀的应用:喜欢更简单的模型到复杂的。

>>> from sklearn import linear_model
>>> regr = linear_model.Lasso(alpha=.3)
>>> regr.fit(diabetes_X_train, diabetes_y_train)
Lasso(...)
>>> regr.coef_ # very sparse coefficients
array([ 0. , -0. , 497.34075682, 199.17441034,
-0. , -0. , -118.89291545, 0. ,
430.9379595 , 0. ])
>>> regr.score(diabetes_X_test, diabetes_y_test)
0.5510835453...

是非常类似于线性回归(最小二乘法)的得分:

>>> lin = linear_model.LinearRegression()
>>> lin.fit(diabetes_X_train, diabetes_y_train)
LinearRegression(...)
>>> lin.score(diabetes_X_test, diabetes_y_test)
0.5850753022...

同一问题的不同算法

可以使用不同的算法来解决相同的数学问题。例如,sklearn中的Lasso对象使用坐标下降方法解决套索回归,这对大型数据集是有效的。然而,sklearn还提供LassoLARS对象,使用LARS对于其中估计的权重向量非常稀疏的问题非常有效,这是非常少的观察的问题。

3.6.7. 模型选择:选择估计量及其参数

3.6.7.1. 网格搜索和交叉验证估计量

3.6.7.1.2. Cross-validated estimators

可以在逐个算法的基础上更有效地进行交叉验证以设置参数。这就是为什么对于某些估计量,scikit-learn暴露“CV”估计量,通过交叉验证自动设置它们的参数:

>>> from sklearn import linear_model, datasets
>>> lasso = linear_model.LassoCV()
>>> diabetes = datasets.load_diabetes()
>>> X_diabetes = diabetes.data
>>> y_diabetes = diabetes.target
>>> lasso.fit(X_diabetes, y_diabetes)
LassoCV(alphas=None, ...)
>>> # The estimator chose automatically its lambda:
>>> lasso.alpha_
0.012...

这些估计量被称为类似于它们的对应物,'CV'附加到他们的名字。

练习

在糖尿病数据集中,找到最佳正则化参数alpha。