科学数据处理统计学习指南

统计学习

机器学习是一项越来越重要的技术,因为实验科学面临的数据集规模正在迅速增长。 它所解决的问题包括建立链接不同观察值的预测功能,对观察值进行分类或学习未标记数据集中的结构。

本教程将探讨统计学习,以及将机器学习技术用于统计推断的目的:在手头的数据上得出结论。

Scikit-learn是一个Python模块,在紧密结合的科学Python程序包世界(NumPy,SciPy,matplotlib)中集成了经典的机器学习算法。

统计学习:scikit-learn中的设置和估计对象

数据集

Scikit-learn处理来自一个或多个以2D数组表示的数据集的学习信息。它们可以理解为多维观测的列表。我们说这些数组的第一个轴是样本轴,而第二个是特征轴。

scikit-learn附带的一个简单示例:iris数据集:

from sklearn import datasets
iris = datasets.load_iris()
data = iris.data
data.shape

输出:

(150,4)

它由150个鸢尾花的观察数据组成,每个观察都由4个特征描述:它们的萼片和花瓣的长度和宽度,详细信息请参见iris.DESCR。

当数据最初不是(n_samples,n_features)形状时,需要对其进行预处理,以供scikit-learn使用。

重塑数据的一个例子是数字数据集:

数字数据集由1797个8x8手写数字图像组成,如图所示:

digits = datasets.load_digits()
digits.images.shape

import matplotlib.pyplot as plt 
plt.imshow(digits.images[-1], cmap=plt.cm.gray_r) 

输出:

(179788)

<matplotlib.image.AxesImage object at ...>

为了将此数据集与scikit-learn一起使用,我们将每个8x8图像转换为长度为64的特征向量:

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

估计对象

拟合数据:scikit-learn实现的主要API是估算器。估计器是从数据中学习的任何对象。它可以是分类,回归或聚类算法,也可以是从原始数据中提取/过滤有用特征的转换器。

所有估算器对象都公开一个带数据集(通常为二维数组)的fit方法:

estimator.fit(data)

估算器参数:可以在实例化估计器或通过修改相应属性来设置估计器的所有参数:

estimator = Estimator(param1 = 1,param2 = 2
estimator.param1

输出:

1

估计出的参数:当数据装有估计器时,参数是根据现有数据估计的。所有估计的参数都是估计对象的属性,其下划线结尾:

estimator.estimated_param_

有监督的学习:从高维观测值预测输出变量

监督学习中解决的问题

监督学习包括学习两个数据集之间的链接:观测数据X和我们试图预测的外部变量y,通常称为“目标”或“标签”。 y通常是长度为n_samples的一维数组。

scikit-learn中所有受监督的估计器都执行fit(X,y)方法以拟合模型,并执行predict(X)方法,给定未标记的观察值X,该方法返回预测的标记y。

词汇:分类和回归

如果预测任务是将观察结果分类为一组有限标签,换句话说就是“命名”观察到的对象,则该任务称为分类任务。另一方面,如果目标是预测连续目标变量,则称其为回归任务。

在scikit-learn中进行分类时,y是整数或字符串的向量。

注意:有关scikit-learn中使用的基本机器学习词汇的快速指南,请参见scikit-learn机器学习简介教程。

最近邻和维度诅咒

分类鸢尾花数据集: 鸢尾花数据集是一项分类任务,包括从其花瓣和萼片的长度和宽度中识别出3种不同类型的鸢尾花(Setosa,Versicolour和Virginica):

import numpy as np
from sklearn import datasets
iris_X, iris_y = datasets.load_iris(return_X_y=True)
np.unique(iris_y)

输出:

array([012])

k近邻分类器

最简单的分类器是最近邻分类器:给定新的观测值X_test,在训练集中(即用于训练估计器的数据)找到具有最近特征向量的观测值。(有关这种类型的分类器的更多信息,请参见在线Scikit-learn文档的Nearest Neighbors部分。)

训练集和测试集

在尝试使用任何学习算法进行实验时,重要的是不要在用于拟合估算器的数据上测试估算器的预测,因为这不会评估新数据上估算器的性能。 这就是为什么数据集经常被分成训练和测试数据的原因。

KNN(k个最近邻)分类示例:

# 在训练和测试数据中分割鸢尾花数据
# 随机排列,随机分割数据
np.random.seed(0)
indices = np.random.permutation(len(iris_X))
iris_X_train = iris_X[indices[:-10]]
iris_y_train = iris_y[indices[:-10]]
iris_X_test = iris_X[indices[-10:]]
iris_y_test = iris_y[indices[-10:]]

# 创建并拟合最近邻分类器
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
knn.fit(iris_X_train, iris_y_train)

knn.predict(iris_X_test)

iris_y_test

输出:

KNeighborsClassifier()

array([1210002120])

array([1110002120])

维度诅咒

为了使估算器有效,您需要相邻点之间的距离小于某个值,这取决于问题。在一个维度上,这平均需要 点。在上述 -NN 示例的上下文中,如果仅通过一个值在0到1范围内的特征和训练观察来描述数据,则新数据将比距离远出。因此,与类间特征变化的规模相比,最近的邻居决策规则将很快变得有效。

如果要素数量为,则现在需要 个点。假设我们在一个维度上需要10个点:现在,在维度的空间上则需要个点才能铺平[0,1]空间。随着变得越来越大,一个好的估计量所需的训练点数呈指数增长。

例如,如果每个点仅是一个数字(8个字节),那么在大约的维度上有效的-NN估计量将需要比整个互联网的当前估计大小(±1000艾字节左右)更多的训练数据。

这称为维数诅咒,是机器学习解决的核心问题。

线性模型:从回归到稀疏

糖尿病数据集

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

diabetes_X, diabetes_y = datasets.load_diabetes(return_X_y=True)
diabetes_X_train = diabetes_X[:-20]
diabetes_X_test  = diabetes_X[-20:]
diabetes_y_train = diabetes_y[:-20]
diabetes_y_test  = diabetes_y[-20:]

当前的任务是根据生理变量预测疾病的进展。

线性回归

LinearRegression最简单的形式是通过调整一组参数将线性模型拟合到数据集,以使模型的残差平方和尽可能小。

线性模型:

  • :数据

  • :目标变量

  • :系数

  • :观察噪声

from sklearn import linear_model
regr = linear_model.LinearRegression()
regr.fit(diabetes_X_train, diabetes_y_train)

print(regr.coef_)  

# 均方误差
np.mean((regr.predict(diabetes_X_test) - diabetes_y_test)**2)


# 解释方差得分:1是完美预测,0表示X和y之间没有线性关系。
regr.score(diabetes_X_test, diabetes_y_test)

输出:

[   0.30349955 -237.63931533  510.53060544  327.73698041 -814.13170937
  492.81458798  102.84845219  184.60648906  743.51961675   76.09517222]

2004.56760268...

0.5850753022690...

紧缩

如果每个维度的数据点很少,则观测值中的噪声会引起高方差:

X = np.c_[ .51].T
y = [.51]
test = np.c_[ 02].T
regr = linear_model.LinearRegression()

import matplotlib.pyplot as plt 
plt.figure() 

np.random.seed(0)
for _ in range(6): 
    this_X = .1 * np.random.normal(size=(21)) + X
    regr.fit(this_X, y)
    plt.plot(test, regr.predict(test)) 
    plt.scatter(this_X, y, s=3)  

高维统计学习的一种解决方案是将回归系数缩小为零:任意两个随机选择的观察值很可能是不相关的。 这称为Ridge回归:

regr = linear_model.Ridge(alpha=.1)

plt.figure() 

np.random.seed(0)
for _ in range(6): 
    this_X = .1 * np.random.normal(size=(21)) + X
    regr.fit(this_X, y)
    plt.plot(test, regr.predict(test)) 
    plt.scatter(this_X, y, s=3

这是偏差/方差折衷的一个示例:脊alpha参数越大,偏差越大,方差越小。

我们可以选择α以最大程度地减少遗漏的错误,这次使用糖尿病数据集而不是我们的综合数据:

alphas = np.logspace(-4-16)
print([regr.set_params(alpha=alpha)
           .fit(diabetes_X_train, diabetes_y_train)
           .score(diabetes_X_test, diabetes_y_test)
       for alpha in alphas])

输出:

[0.5851110683883..., 0.5852073015444..., 0.5854677540698...,
 0.5855512036503..., 0.5830717085554..., 0.57058999437...]

注意:捕获阻止模型泛化为新数据的拟合参数噪声称为过拟合。 脊回归带来的偏差称为正则化。

稀疏性

注意:完整的糖尿病数据集的表示将涉及11个维度(10个特征维度和一个目标变量)。 很难就这种表示法建立一种直觉,但记住这将是一个相当空的空间,这可能会很有用。

我们可以看到,尽管特征2在整个模型中具有很强的系数,但是当与特征1一起考虑时,它传达的y信息很少。

为了改善问题的状况(即减轻维度诅咒),仅选择信息性特征并将非信息性特征(例如特征2设置为0)会很有趣。Ridge回归会减少其贡献,但不会设置 他们为零。 另一种惩罚方法称为Lasso(最小绝对收缩和选择算子),可以将一些系数设置为零。 这种方法称为稀疏方法,稀疏性可以看作是Occam剃刀的一种应用:更喜欢简单的模型。

regr = linear_model.Lasso()
scores = [regr.set_params(alpha=alpha)
              .fit(diabetes_X_train, diabetes_y_train)
              .score(diabetes_X_test, diabetes_y_test)
          for alpha in alphas]
best_alpha = alphas[scores.index(max(scores))]
regr.alpha = best_alpha
regr.fit(diabetes_X_train, diabetes_y_train)

print(regr.coef_)

输出:

Lasso(alpha=0.025118864315095794)

[   0.         -212.43764548  517.19478111  313.77959962 -160.8303982    -0.
 -187.19554705   69.38229038  508.66011217   71.84239008]

针对同一问题的不同算法

可以使用不同的算法来解决相同的数学问题。 例如,scikit-learn中的套索对象使用坐标下降法解决了套索回归问题,该方法在大型数据集上非常有效。 但是,scikit-learn还使用LARS算法提供了LassoLars对象,对于估计的权重向量非常稀疏的问题(即观察很少的问题)非常有效。

分类

对于分类,如在标记虹膜任务中一样,线性回归不是正确的方法,因为它将对远离决策边界的数据赋予过多的权重。 线性方法是拟合S型函数或逻辑函数:

输入:

log = linear_model.LogisticRegression(C=1e5)
log.fit(iris_X_train, iris_y_train)

输出:

LogisticRegression(C=100000.0)

这就是知名的逻辑回归:

多标签分类

如果您要预测多个类别,则经常使用的选择是对所有分类器进行拟合,然后使用投票启发法进行最终决策。

逻辑回归的收缩率和稀疏性

C参数控制LogisticRegression对象中的正则化量:C的值较大会导致正则化程度降低。 惩罚=“ l2”给出收缩率(即非稀疏系数),而惩罚=“ l1”给出稀疏性。

练习

尝试用最近的邻居和线性模型对数字数据集进行分类。 忽略最后的10%,并根据这些观察结果测试预测性能。

from sklearn import datasets, neighbors, linear_model

X_digits, y_digits = datasets.load_digits(return_X_y=True)
X_digits = X_digits / X_digits.max()

解决方案:https://scikit-learn.org/stable/_downloads/bfcebce45024b267e8546d6914acfedc/plot_digits_classification_exercise.py

支持向量机(SVM)

线性支持向量机

支持向量机属于判别模型家族:它们试图找到样本的组合以构建一个平面,以最大化两个类别之间的余量。 正则化是由C参数设置的:C的值较小意味着使用分隔线附近的许多或所有观测值来计算裕度(更正则化); C的值较大,表示在接近分隔线的观察值上计算裕度(较少的正则化)。

示例:

在鸢尾花数据集中绘制不同的SVM分类器

SVM可用于回归–SVR(支持向量回归)–或分类–SVC(支持向量分类)。

from sklearn import svm
svc = svm.SVC(kernel='linear')
svc.fit(iris_X_train, iris_y_train)

输出:

SVC(kernel='linear')

警告:归一化数据

对于包括SVM在内的许多估算器而言,对于每个要素而言,拥有具有单位标准差的数据集对于获得良好的预测至关重要。

使用核函数

在要素空间中,类并非总是线性可分离的。 解决方案是建立一个决策函数,该决策函数不是线性的,而是可以是多项式的。 这是使用内核技巧完成的,该技巧可以看作是通过将内核置于观察值上来创建决策能量:

互动范例

参见SVM GUI以下载svm_gui.py;。 使用左右按钮添加两个类别的数据点,拟合模型并更改参数和数据。

练习

尝试使用SVM对虹膜数据集中的第1类和第2类进行分类,并具有2个主要特征。 忽略每堂课的10%,并根据这些观察结果测试预测性能。

警告:课程是有序的,请不要遗漏最后的10%,您只能在一个课程上进行测试。

提示:您可以在网格上使用Decision_function方法来获取一些感觉。

输入:

iris = datasets.load_iris()
X = iris.data
y = iris.target

X = X[y != 0, :2]
y = y[y != 0]

解决方案见:https://scikit-learn.org/stable/_downloads/91f0cd01beb5b964a5e1ece5bdd15499/plot_iris_exercise.py

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

分数和交叉验证的分数

如我们所见,每个估算器都公开一种计分方法,该方法可以判断新数据的拟合(或预测)质量。 越大越好。

from sklearn import datasets, svm
X_digits, y_digits = datasets.load_digits(return_X_y=True)
svc = svm.SVC(C=1, kernel='linear')
svc.fit(X_digits[:-100], y_digits[:-100]).score(X_digits[-100:], y_digits[-100:])

输出:

0.98

为了更好地衡量预测准确性(我们可以将其用作模型拟合优度的代理),我们可以将数据依次分成折叠,用于训练和测试:

import numpy as np
X_folds = np.array_split(X_digits, 3)
y_folds = np.array_split(y_digits, 3)
scores = list()
for k in range(3):
    # We use 'list' to copy, in order to 'pop' later on
    X_train = list(X_folds)
    X_test = X_train.pop(k)
    X_train = np.concatenate(X_train)
    y_train = list(y_folds)
    y_test = y_train.pop(k)
    y_train = np.concatenate(y_train)
    scores.append(svc.fit(X_train, y_train).score(X_test, y_test))
print(scores)

输出:

[0.934..., 0.956..., 0.939...]

这被叫做K折交叉验证。

交叉验证生成器

Scikit-learn具有一组类,这些类可用于生成流行的交叉验证策略的训练/测试索引列表。

他们公开了一个拆分方法,该方法接受要拆分的输入数据集,并为所选交叉验证策略的每次迭代生成训练/测试集索引。

本示例显示了split方法的示例用法。

输入:

from sklearn.model_selection import KFold, cross_val_score
X = ["a""a""a""b""b""c""c""c""c""c"]
k_fold = KFold(n_splits=5)
for train_indices, test_indices in k_fold.split(X):
     print('Train: %s | test: %s' % (train_indices, test_indices))

输出:

Train: [2 3 4 5 6 7 8 9] | test: [0 1]
Train: [0 1 4 5 6 7 8 9] | test: [2 3]
Train: [0 1 2 3 6 7 8 9] | test: [4 5]
Train: [0 1 2 3 4 5 8 9] | test: [6 7]
Train: [0 1 2 3 4 5 6 7] | test: [8 9]

然后可以轻松执行交叉验证:

[svc.fit(X_digits[train], y_digits[train]).score(X_digits[test], y_digits[test]) for train, test in k_fold.split(X_digits)]

输出:

[0.963..., 0.922..., 0.963..., 0.963..., 0.930...]

可以使用cross_val_score帮助器直接计算交叉验证得分。 给定一个估算器,交叉验证对象和输入数据集,cross_val_score将数据重复拆分为一个训练和一个测试集,使用该训练集训练该估算器,并根据测试集计算交叉算子的每次迭代的得分 验证。

默认情况下,估算器的得分方法用于计算各个得分。

请参阅指标模块以了解有关可用评分方法的更多信息。

cross_val_score(svc, X_digits, y_digits, cv=k_fold, n_jobs=-1)

输出:

array([0.963888890.922222220.9637883 , 0.9637883 , 0.93036212])

n_jobs = -1表示将在计算机的所有CPU上调度计算。

可替代地,可以提供计分参数以指定替代的计分方法。

cross_val_score(svc, X_digits, y_digits, cv=k_fold,
                scoring='precision_macro')

输出:

array([0.965782890.927089220.966814760.963628970.93192644])

交叉验证生成器

KFold (n_splits, shuffle, random_state) StratifiedKFold (n_splits, shuffle, random_state) GroupKFold (n_splits)
将其拆分为K折,在K-1上训练,然后在左侧进行测试。 与K折相同,但保留每个折内的类分布。 确保同一组不在测试和培训集中
ShuffleSplit (n_splits, test_size, train_size, random_state) StratifiedShuffleSplit GroupShuffleSplit
根据随机排列生成训练/测试索引。 与shuffle split相同,但保留每次迭代内的类分布。 确保同一组不在测试和培训集中。
LeaveOneGroupOut () LeavePGroupsOut (n_groups) LeaveOneOut ()
采用组数组对观察进行分组。 忽略P组 忽略指定的一个观察值。
LeavePOut (p) PredefinedSplit
忽略P个观察值 根据预定义的拆分生成训练/测试索引。

练习

在数字数据集上,绘制具有线性核的SVC估计量的交叉验证得分作为参数C的函数(使用点的对数网格,范围为1到10)。

import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn import datasets, svm

X, y = datasets.load_digits(return_X_y=True)

svc = svm.SVC(kernel='linear')
C_s = np.logspace(-10010)

scores = list()

解决方案见链接:手写数据集上的交叉验证

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

网格搜索

scikit-learn提供了一个对象,该对象在给定数据的情况下,在参数网格上的估计器拟合期间计算分数,并选择参数以最大化交叉验证分数。 该对象在构造期间接受一个估算器,并公开一个估算器API:

from sklearn.model_selection import GridSearchCV, cross_val_score
Cs = np.logspace(-6-110)
clf = GridSearchCV(estimator=svc, param_grid=dict(C=Cs),
                   n_jobs=-1)
clf.fit(X_digits[:1000], y_digits[:1000])        

clf.best_score_                                  

clf.best_estimator_.C                            


# 测试集的预测性能不如训练集
clf.score(X_digits[1000:], y_digits[1000:])      

输出:

GridSearchCV(cv=None,...)

0.925...

0.0077...

0.943...

默认情况下,GridSearchCV使用3倍交叉验证。但是,如果检测到通过了分类器而不是回归器,则使用分层的3倍。默认值将在版本0.22中更改为5倍交叉验证。

嵌套交叉验证

cross_val_score(clf, X_digits, y_digits) 

输出:

array([0.938..., 0.963..., 0.944...])
并行执行两个交叉验证循环:一个由GridSearchCV估计器设置gamma,另一个由cross_val_score来测量估计器的预测性能。所得分数是对新数据的预测分数的无偏估计。

警告:不能嵌套使用并行计算的对象(n_jobs不同于1)。

交叉验证的估计量

可以在逐个算法的基础上更高效地完成交叉验证以设置参数。这就是为什么对于某些估计器,scikit-learn会显示交叉验证:评估通过交叉验证自动设置其参数的估计器性能估计器:

from sklearn import linear_model, datasets
lasso = linear_model.LassoCV()
X_diabetes, y_diabetes = datasets.load_diabetes(return_X_y=True)
lasso.fit(X_diabetes, y_diabetes)

# 估算器自动选择其lambda:
lasso.alpha_

输出:

LassoCV()

0.00375...

这些估算器的名称与对应估算器的名称类似,后缀“ CV”。

练习

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

奖励:您对选择出的alpha有多少信心?

from sklearn import datasets
from sklearn.linear_model import LassoCV
from sklearn.linear_model import Lasso
from sklearn.model_selection import KFold
from sklearn.model_selection import GridSearchCV

X, y = datasets.load_diabetes(return_X_y=True)
X = X[:150]

解决方案:糖尿病数据集上的交叉验证练习

无监督学习:寻求数据表示

聚类:将观察分组在一起

聚类中解决的问题

在给定鸢尾花数据集的情况下,如果我们知道虹膜有3种类型,但没有分类学家来标记它们的话:我们可以尝试进行聚类任务:将观察结果分成分离良好的一组,称为聚类。

K均值聚类

请注意,存在许多不同的聚类标准和相关算法。 最简单的聚类算法是K-means。

输入:

from sklearn import cluster, datasets
X_iris, y_iris = datasets.load_iris(return_X_y=True)

k_means = cluster.KMeans(n_clusters=3)
k_means.fit(X_iris)

print(k_means.labels_[::10])

print(y_iris[::10])

输出:

KMeans(n_clusters=3)

[1 1 1 1 1 0 0 0 0 0 2 2 2 2 2]

[0 0 0 0 0 1 1 1 1 1 2 2 2 2 2]

警告:聚类绝对不能保证恢复基本事实(译者注:即找到真实标签)。 首先,很难选择正确数量的群集。 其次,尽管scikit-learn使用了几种技巧来缓解此问题,但是该算法对初始化很敏感,并且可以陷入局部最小值。

不要过度解读聚类结果。

应用示例:矢量量化

一般而言,尤其是KMeans,聚类可以看作是选择少量样本来压缩信息的一种方式。 该问题有时称为矢量量化。 例如,这可以用于后继图像:

import scipy as sp
try:
   face = sp.face(gray=True)
except AttributeError:
   from scipy import misc
   face = misc.face(gray=True)
X = face.reshape((-11)) # We need an (n_sample, n_feature) array
k_means = cluster.KMeans(n_clusters=5, n_init=1)
k_means.fit(X)

values = k_means.cluster_centers_.squeeze()
labels = k_means.labels_
face_compressed = np.choose(labels, values)
face_compressed.shape = face.shape

输出:

KMeans(n_clusters=5, n_init=1)

分层聚集聚类:Ward

层次聚类方法是一种聚类分析,旨在建立聚类的层次。通常,此技术的各种方法是:

  • 集聚-自下而上的方法:每个观察都从其自己的簇开始,并且以最小化链接标准的方式迭代地合并簇。当感兴趣的簇仅由少量观察组成时,这种方法特别有趣。当簇数很大时,它的计算效率比k均值高得多。

  • 分裂-自上而下的方法:所有观察都始于一个簇,当一个簇向下移动时,它将被迭代地拆分。对于估计大量聚类,此方法既缓慢(由于所有观察都是从一个聚类开始,然后递归拆分),而且在统计上是不适定的。

连接受限的集群

通过聚集聚类,可以通过提供连通性图来指定可以将哪些样本聚在一起。 scikit-learn中的图由它们的邻接矩阵表示。通常,使用稀疏矩阵。例如,在对图像进行聚类时,这对于检索连接的区域(有时也称为连接的组件)很有用。

from skimage.data import coins
from scipy.ndimage.filters import gaussian_filter
from skimage.transform import rescale
rescaled_coins = rescale(
    gaussian_filter(coins(), sigma=2),
    0.2, mode='reflect', anti_aliasing=False, multichannel=False
)
X = np.reshape(rescaled_coins, (-11))

我们需要图像的矢量化版本。 'rescaled_coins'是硬币图像的缩小版本,以加快处理速度:

from sklearn.feature_extraction import grid_to_graph
connectivity = grid_to_graph(*rescaled_coins.shape)

定义数据的图形结构。连接到邻近的像素:

n_clusters = 27  #簇的数量

from sklearn.cluster import AgglomerativeClustering
ward = AgglomerativeClustering(n_clusters=n_clusters, linkage='ward',
                               connectivity=connectivity)
ward.fit(X)

label = np.reshape(ward.labels_, rescaled_coins.shape)

输出:

AgglomerativeClustering(connectivity=..., n_clusters=27)

功能集聚

我们已经看到稀疏性可以用来减轻维数的诅咒,即与特征数量相比,观测值不足。另一种方法是将相似的特征融合在一起:特征集聚。可以通过在特征方向上进行聚类(换句话说,对转置后的数据进行聚类)来实现此方法。

digits = datasets.load_digits()
images = digits.images
X = np.reshape(images, (len(images), -1))
connectivity = grid_to_graph(*images[0].shape)

agglo = cluster.FeatureAgglomeration(connectivity=connectivity,
                                     n_clusters=32)
agglo.fit(X)

X_reduced = agglo.transform(X)

X_approx = agglo.inverse_transform(X_reduced)
images_approx = np.reshape(X_approx, images.shape)

输出:

FeatureAgglomeration(connectivity=..., n_clusters=32)

转换和逆转换(inverse_transform)方法

一些估计器会公开一种转换方法,例如以减少数据集的维数。

分解:从信号到分量和负载

组件(成分/特征)和负载

如果X是我们的多元数据,那么我们要解决的问题是在不同的观察基础上重写它:我们想学习载荷L和一组分量C,使得X = LC。存在选择的不同标准组件

主成分分析:PCA

主成分分析(PCA)选择解释信号中最大方差的连续成分。

上面观察到的点云在一个方向上非常平坦:三个单变量特征之一几乎可以使用另外两个来精确计算。 PCA寻找数据不一致的方向。

当用于转换数据时,PCA可以通过投影在主要子空间上来降低数据的维数。

#创建一个仅2个有用维度的信号

x1 = np.random.normal(size=100)
x2 = np.random.normal(size=100)
x3 = x1 + x2
X = np.c_[x1, x2, x3]

from sklearn import decomposition
pca = decomposition.PCA()
pca.fit(X)

print(pca.explained_variance_) 

输出:

[  2.18565811e+00   1.19346747e+00   8.43026679e-32]

如我们所见,只有前两个组件是有用的。

pca.n_components = 2
X_reduced = pca.fit_transform(X)
X_reduced.shape

输出:

(100, 2)

独立成分分析:ICA

独立组件分析(ICA)选择组件,以便它们的载荷分布具有最大数量的独立信息。 它能够恢复非高斯独立信号:

# 获取样本数据
import numpy as np
from scipy import signal
time = np.linspace(0102000)
s1 = np.sin(2 * time)  # 信号1 : 正弦信号
s2 = np.sign(np.sin(3 * time))  # 信号2:方波信号
s3 = signal.sawtooth(2 * np.pi * time)  # 信号3: 锯齿信号
S = np.c_[s1, s2, s3]
S += 0.2 * np.random.normal(size=S.shape)  # 增加噪音
S /= S.std(axis=0)  # 标准化数据
# 混合数据
A = np.array([[111], [0.521], [1.512]])  # 混和矩阵
X = np.dot(S, A.T)  # 获取观测值

# 计算ICA
ica = decomposition.FastICA()
S_ = ica.fit_transform(X)  # 得到预测结果
A_ = ica.mixing_.T
np.allclose(X,  np.dot(S_, A_) + ica.mean_)

输出:

True

全部放在一起

管道

我们已经看到,一些估计器可以转换数据,并且一些估计器可以预测变量。 我们还可以创建组合的估计量:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV


# 定义管道以搜索PCA截断和分类器正则化的最佳组合。
pca = PCA()
# 将公差设置为较大的值可以使示例更快
logistic = LogisticRegression(max_iter=10000, tol=0.1)
pipe = Pipeline(steps=[('pca', pca), ('logistic', logistic)])

X_digits, y_digits = datasets.load_digits(return_X_y=True)

# 可以使用__分隔的参数名称来设置管道的参数:
param_grid = {
    'pca__n_components': [515304564],
    'logistic__C': np.logspace(-444),
}
search = GridSearchCV(pipe, param_grid, n_jobs=-1)
search.fit(X_digits, y_digits)
print("Best parameter (CV score=%0.3f):" % search.best_score_)
print(search.best_params_)

# 绘制PCA色谱
pca.fit(X_digits)

fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True, figsize=(66))
ax0.plot(np.arange(1, pca.n_components_ + 1),
         pca.explained_variance_ratio_, '+', linewidth=2)
ax0.set_ylabel('PCA explained variance ratio')

ax0.axvline(search.best_estimator_.named_steps['pca'].n_components,
            linestyle=':', label='n_components chosen')
ax0.legend(prop=dict(size=12))

特征脸的人脸识别

本示例中使用的数据集是“未经处理的、有标签的人脸”(也称为LFW)的预处理摘录:

http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz(233MB)

"""
===================================================
使用特征脸和SVM的脸部识别示例
===================================================

本示例中使用的数据集是“贴有标签的未经处理的面孔”,又名LFW_:

   http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz(233MB)

.._ LFW:http://vis-www.cs.umass.edu/lfw/

数据集中排名前5名的人员的预期结果:

================================================== =

================== ============ ======= ========== =======
                   precision    recall  f1-score   support
================== ============ ======= ========== =======
     Ariel Sharon       0.67      0.92      0.77        13
     Colin Powell       0.75      0.78      0.76        60
  Donald Rumsfeld       0.78      0.67      0.72        27
    George W Bush       0.86      0.86      0.86       146
Gerhard Schroeder       0.76      0.76      0.76        25
      Hugo Chavez       0.67      0.67      0.67        15
       Tony Blair       0.81      0.69      0.75        36

      avg / total       0.80      0.80      0.80       322
================== ============ ======= ========== =======

"""

from time import time
import logging
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import fetch_lfw_people
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn.svm import SVC


print(__doc__)

# 在标准输出上显示进度日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')


# #############################################################################
# 下载数据(如果尚未存储在磁盘上)并将其作为numpy数组加载

lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)

# 内省图像数组以找到形状(用于绘制)
n_samples, h, w = lfw_people.images.shape

# 对于机器学习,我们直接使用这2个数据(因为相对像素位置信息被该模型忽略)
X = lfw_people.data
n_features = X.shape[1]

# 要预测的标签是该人的身份证
y = lfw_people.target
target_names = lfw_people.target_names
n_classes = target_names.shape[0]

print("Total dataset size:")
print("n_samples: %d" % n_samples)
print("n_features: %d" % n_features)
print("n_classes: %d" % n_classes)


# #############################################################################
# 使用分层k折分为训练集和测试集

# 分割需练级与测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42)


# #############################################################################
# 在人脸数据集(视为未标记数据集)上计算PCA(特征脸):无监督特征提取/降维
n_components = 150

print("Extracting the top %d eigenfaces from %d faces"
      % (n_components, X_train.shape[0]))
t0 = time()
pca = PCA(n_components=n_components, svd_solver='randomized',
          whiten=True).fit(X_train)
print("done in %0.3fs" % (time() - t0))

eigenfaces = pca.components_.reshape((n_components, h, w))

print("Projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
print("done in %0.3fs" % (time() - t0))


# #############################################################################
# 训练SVM分类模型

print("Fitting the classifier to the training set")
t0 = time()
param_grid = {'C': [1e35e31e45e41e5],
              'gamma': [0.00010.00050.0010.0050.010.1], }
clf = GridSearchCV(
    SVC(kernel='rbf', class_weight='balanced'), param_grid
)
clf = clf.fit(X_train_pca, y_train)
print("done in %0.3fs" % (time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_)


# #############################################################################
# 对测试集中的模型质量进行定量评估

print("Predicting people's names on the test set")
t0 = time()
y_pred = clf.predict(X_test_pca)
print("done in %0.3fs" % (time() - t0))

print(classification_report(y_test, y_pred, target_names=target_names))
print(confusion_matrix(y_test, y_pred, labels=range(n_classes)))


# #############################################################################
# 使用matplotlib对预测进行定性评估

def plot_gallery(images, titles, h, w, n_row=3, n_col=4):
    """Helper function to plot a gallery of portraits"""
    plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))
    plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
    for i in range(n_row * n_col):
        plt.subplot(n_row, n_col, i + 1)
        plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
        plt.title(titles[i], size=12)
        plt.xticks(())
        plt.yticks(())


# 在测试集的一部分上绘制预测结果

def title(y_pred, y_test, target_names, i):
    pred_name = target_names[y_pred[i]].rsplit(' '1)[-1]
    true_name = target_names[y_test[i]].rsplit(' '1)[-1]
    return 'predicted: %s\ntrue:      %s' % (pred_name, true_name)

prediction_titles = [title(y_pred, y_test, target_names, i)
                     for i in range(y_pred.shape[0])]

plot_gallery(X_test, prediction_titles, h, w)

# 绘制最有意义的特征脸图库

eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)

plt.show()

输出:

数据集中排名前5名的人员的预期结果:

                   precision    recall  f1-score   support

Gerhard_Schroeder       0.91      0.75      0.82        28
  Donald_Rumsfeld       0.84      0.82      0.83        33
       Tony_Blair       0.65      0.82      0.73        34
     Colin_Powell       0.78      0.88      0.83        58
    George_W_Bush       0.93      0.86      0.90       129

      avg / total       0.86      0.84      0.85       282

未解决的问题:股票市场结构

我们可以预测给定时间内Google的股价变化吗?

股市结构可视化

寻求帮助

项目邮件清单

如果您遇到scikit-learn的错误,或者需要在文档字符串或在线文档中进行说明,请随时在邮件列表中询问。

机器学习从业者问答社区

网站 说明
Quora.com Quora有一个与机器学习相关的问题的主题,其中还包含一些有趣的讨论:https://www.quora.com/topic/Machine-Learning
Stack Exchange Stack Exchange系列站点托管用于机器学习问题的多个子域。

– _“斯坦福大学的吴安德教授教授的一本优秀的免费在线机器学习课程”:https://www.coursera.org/learn/machine-learning

– _“另一种出色的免费在线课程,采用了更通用的人工智能方法”:https://www.udacity.com/course/intro-to-artificial-intelligence–cs271