Machine-Learning-Mastery-Sklearn-教程-十-

98 阅读1小时+

Machine Learning Mastery Sklearn 教程(十)

原文:Machine Learning Mastery

协议:CC BY-NC-SA 4.0

使用标签传播的半监督学习

原文:machinelearningmastery.com/semi-superv…

半监督学习是指试图同时利用已标记和未标记训练数据的算法。

半监督学习算法不像监督学习算法那样只能从有标签的训练数据中学习。

半监督学习的一种流行方法是创建一个连接训练数据集中的示例的图,并通过图的边缘传播已知的标签来标记未标记的示例。这种半监督学习方法的一个例子是用于分类预测建模的标签传播算法

在本教程中,您将发现如何将标签传播算法应用于半监督学习分类数据集。

完成本教程后,您将知道:

  • 标签传播半监督学习算法如何工作的直觉。
  • 如何使用监督学习算法开发半监督分类数据集并建立表现基线。
  • 如何开发和评估标签传播算法,并使用模型输出来训练监督学习算法。

我们开始吧。

Semi-Supervised Learning With Label Spreading

带有标签传播的半监督学习 图片由 Jernej Furman 提供,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 标签扩展算法
  2. 半监督分类数据集
  3. 半监督学习中的标签传播

标签扩展算法

标签传播是一种半监督学习算法。

该算法是由周等人在 2003 年的论文《具有局部和全局一致性的学习》中提出的

半监督学习的更广泛方法的直觉是,输入空间中的邻近点应该具有相同的标签,并且输入空间中的相同结构或流形中的点应该具有相同的标签。

半监督学习问题的关键是一致性的先验假设,这意味着:(1)附近的点很可能有相同的标签;以及(2)相同结构上的点(通常称为簇或流形)可能具有相同的标签。

——具有局部和全局一致性的学习,2003。

标签传播的灵感来自实验心理学的一项技术,叫做传播激活网络。

这个算法可以从实验心理学传播激活网络的角度直观地理解。

——具有局部和全局一致性的学习,2003。

数据集中的点根据它们在输入空间中的相对距离连接成一个图形。图的权重矩阵是对称归一化的,很像谱聚类。信息通过图形传递,图形适于捕捉输入空间中的结构。

该方法与半监督学习的标签传播算法非常相似。

另一个类似的标签传播算法由 Zhou 等人给出:在每一步,节点 I 接收来自其邻居 j 的贡献(由边(I,j)的归一化权重加权),以及由其初始值给出的额外的小贡献

—第 196 页,半监督学习,2006。

收敛后,基于传递最多信息的节点应用标签。

最后,每个未标记点的标签被设置为在迭代过程中接收到最多信息的类别。

——具有局部和全局一致性的学习,2003。

现在我们已经熟悉了标签传播算法,让我们看看如何在项目中使用它。首先,我们必须定义一个半监督分类数据集。

半监督分类数据集

在本节中,我们将为半监督学习定义一个数据集,并在该数据集上建立一个表现基线。

首先,我们可以使用make _ classion()函数定义一个合成分类数据集。

我们将用两个类(二进制分类)和两个输入变量以及 1000 个示例来定义数据集。

...
# define dataset
X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1)

接下来,我们将数据集分割成训练数据集和测试数据集,分割比例为 50-50(例如,每组 500 行)。

...
# split into train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y)

最后,我们将训练数据集再次分成两部分,一部分有标签,另一部分我们假装没有标签。

...
# split train into labeled and unlabeled
X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train)

将这些联系在一起,下面列出了准备半监督学习数据集的完整示例。

# prepare semi-supervised learning dataset
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
# define dataset
X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1)
# split into train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y)
# split train into labeled and unlabeled
X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train)
# summarize training set size
print('Labeled Train Set:', X_train_lab.shape, y_train_lab.shape)
print('Unlabeled Train Set:', X_test_unlab.shape, y_test_unlab.shape)
# summarize test set size
print('Test Set:', X_test.shape, y_test.shape)

运行该示例准备数据集,然后总结三个部分的形状。

结果证实,我们有一个 500 行的测试数据集、一个 250 行的标记训练数据集和 250 行的未标记数据。

Labeled Train Set: (250, 2) (250,)
Unlabeled Train Set: (250, 2) (250,)
Test Set: (500, 2) (500,)

一个有监督的学习算法只有 250 行来训练一个模型。

半监督学习算法将具有 250 个标记行以及 250 个未标记行,这些行可以以多种方式用于改进标记的训练数据集。

接下来,我们可以使用仅适用于标记训练数据的监督学习算法,在半监督学习数据集上建立表现基线。

这一点很重要,因为我们期望半监督学习算法的表现优于仅适用于标记数据的监督学习算法。如果不是这样,那么半监督学习算法就没有技巧。

在这种情况下,我们将使用逻辑回归算法来拟合训练数据集的标记部分。

...
# define model
model = LogisticRegression()
# fit model on labeled dataset
model.fit(X_train_lab, y_train_lab)

然后,该模型可用于对整个保持测试数据集进行预测,并使用分类精确率进行评估。

...
# make predictions on hold out test set
yhat = model.predict(X_test)
# calculate score for test set
score = accuracy_score(y_test, yhat)
# summarize score
print('Accuracy: %.3f' % (score*100))

将这些联系在一起,下面列出了在半监督学习数据集上评估监督学习算法的完整示例。

# baseline performance on the semi-supervised learning dataset
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.linear_model import LogisticRegression
# define dataset
X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1)
# split into train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y)
# split train into labeled and unlabeled
X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train)
# define model
model = LogisticRegression()
# fit model on labeled dataset
model.fit(X_train_lab, y_train_lab)
# make predictions on hold out test set
yhat = model.predict(X_test)
# calculate score for test set
score = accuracy_score(y_test, yhat)
# summarize score
print('Accuracy: %.3f' % (score*100))

运行该算法使模型适合标记的训练数据集,并在保持数据集上对其进行评估,并打印分类精确率。

:考虑到算法或评估程序的随机性,或数值精确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到该算法实现了大约 84.8%的分类准确率。

我们期望一种有效的半监督学习算法能获得比这更好的精确率。

Accuracy: 84.800

接下来,让我们探索如何将标签传播算法应用于数据集。

半监督学习中的标签传播

标签传播算法可通过标签传播类在 Sklearn Python 机器学习库中获得。

通过调用 fit() 函数,该模型可以像任何其他分类模型一样进行拟合,并通过 predict() 函数用于对新数据进行预测。

...
# define model
model = LabelSpreading()
# fit model on training dataset
model.fit(..., ...)
# make predictions on hold out test set
yhat = model.predict(...)

重要的是,提供给 fit() 函数的训练数据集必须包括有序编码的已标记示例(按照正常情况)和标记为-1 的未标记示例。

然后,作为拟合模型的一部分,模型将确定未标记示例的标签。

模型拟合后,训练数据集中已标记和未标记数据的估计标签可通过标签预标记类上的“转导 _ ”属性获得。

...
# get labels for entire training dataset data
tran_labels = model.transduction_

现在我们已经熟悉了如何在 Sklearn 中使用标签传播算法,让我们看看如何将其应用于我们的半监督学习数据集。

首先,我们必须准备训练数据集。

我们可以将训练数据集的输入数据连接成一个数组。

...
# create the training dataset input
X_train_mixed = concatenate((X_train_lab, X_test_unlab))

然后,我们可以为训练数据集中未标记部分的每一行创建一个-1 值(未标记)的列表。

...
# create "no label" for unlabeled data
nolabel = [-1 for _ in range(len(y_test_unlab))]

然后,该列表可以与来自训练数据集标记部分的标签连接起来,以对应于训练数据集的输入数组。

...
# recombine training dataset labels
y_train_mixed = concatenate((y_train_lab, nolabel))

我们现在可以在整个训练数据集上训练标签预定义模型。

...
# define model
model = LabelSpreading()
# fit model on training dataset
model.fit(X_train_mixed, y_train_mixed)

接下来,我们可以使用该模型对保持数据集进行预测,并使用分类精确率评估该模型。

...
# make predictions on hold out test set
yhat = model.predict(X_test)
# calculate score for test set
score = accuracy_score(y_test, yhat)
# summarize score
print('Accuracy: %.3f' % (score*100))

将这些联系在一起,下面列出了在半监督学习数据集上评估标签传播的完整示例。

# evaluate label spreading on the semi-supervised learning dataset
from numpy import concatenate
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.semi_supervised import LabelSpreading
# define dataset
X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1)
# split into train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y)
# split train into labeled and unlabeled
X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train)
# create the training dataset input
X_train_mixed = concatenate((X_train_lab, X_test_unlab))
# create "no label" for unlabeled data
nolabel = [-1 for _ in range(len(y_test_unlab))]
# recombine training dataset labels
y_train_mixed = concatenate((y_train_lab, nolabel))
# define model
model = LabelSpreading()
# fit model on training dataset
model.fit(X_train_mixed, y_train_mixed)
# make predictions on hold out test set
yhat = model.predict(X_test)
# calculate score for test set
score = accuracy_score(y_test, yhat)
# summarize score
print('Accuracy: %.3f' % (score*100))

运行该算法使模型适合整个训练数据集,并在保持数据集上对其进行评估,并打印分类精确率。

:考虑到算法或评估程序的随机性,或数值精确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到标签传播模型实现了大约 85.4%的分类精确率,这略高于仅在实现了大约 84.8%的精确率的标签训练数据集上的逻辑回归拟合。

Accuracy: 85.400

目前为止一切顺利。

对于半监督模型,我们可以使用的另一种方法是获取训练数据集的估计标签,并拟合监督学习模型。

回想一下,我们可以从标签传播模型中检索整个训练数据集的标签,如下所示:

...
# get labels for entire training dataset data
tran_labels = model.transduction_

然后,我们可以使用这些标签以及所有输入数据来训练和评估监督学习算法,例如逻辑回归模型。

希望适合整个训练数据集的监督学习模型将获得比单独的半监督学习模型更好的表现。

...
# define supervised learning model
model2 = LogisticRegression()
# fit supervised learning model on entire training dataset
model2.fit(X_train_mixed, tran_labels)
# make predictions on hold out test set
yhat = model2.predict(X_test)
# calculate score for test set
score = accuracy_score(y_test, yhat)
# summarize score
print('Accuracy: %.3f' % (score*100))

将这些联系在一起,下面列出了使用估计的训练集标签来训练和评估监督学习模型的完整示例。

# evaluate logistic regression fit on label spreading for semi-supervised learning
from numpy import concatenate
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.semi_supervised import LabelSpreading
from sklearn.linear_model import LogisticRegression
# define dataset
X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1)
# split into train and test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y)
# split train into labeled and unlabeled
X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train)
# create the training dataset input
X_train_mixed = concatenate((X_train_lab, X_test_unlab))
# create "no label" for unlabeled data
nolabel = [-1 for _ in range(len(y_test_unlab))]
# recombine training dataset labels
y_train_mixed = concatenate((y_train_lab, nolabel))
# define model
model = LabelSpreading()
# fit model on training dataset
model.fit(X_train_mixed, y_train_mixed)
# get labels for entire training dataset data
tran_labels = model.transduction_
# define supervised learning model
model2 = LogisticRegression()
# fit supervised learning model on entire training dataset
model2.fit(X_train_mixed, tran_labels)
# make predictions on hold out test set
yhat = model2.predict(X_test)
# calculate score for test set
score = accuracy_score(y_test, yhat)
# summarize score
print('Accuracy: %.3f' % (score*100))

运行该算法将半监督模型拟合到整个训练数据集上,然后将监督学习模型拟合到具有推断标签的整个训练数据集上,并在保持数据集上对其进行评估,打印分类精确率。

:考虑到算法或评估程序的随机性,或数值精确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到,半监督模型跟随监督模型的分层方法在保持数据集上实现了大约 85.8%的分类精确率,略好于单独使用的半监督学习算法,该算法实现了大约 85.6%的精确率。

Accuracy: 85.800

通过调优 LabelSpreading 模型的超参数,能达到更好的效果吗? 让我知道你在下面的评论中发现了什么。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

报纸

蜜蜂

文章

摘要

在本教程中,您发现了如何将标签传播算法应用于半监督学习分类数据集。

具体来说,您了解到:

  • 标签传播半监督学习算法如何工作的直觉。
  • 如何使用监督学习算法开发半监督分类数据集并建立表现基线。
  • 如何开发和评估标签传播算法,并使用模型输出来训练监督学习算法。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

数据集大小 VS 模型表现的敏感性分析

原文:machinelearningmastery.com/sensitivity…

机器学习模型表现通常随着用于预测建模的数据集大小而提高。

这取决于具体的数据集和模型的选择,尽管这通常意味着使用更多的数据可以获得更好的表现,并且使用较小的数据集来估计模型表现的发现通常可以扩展到使用较大的数据集。

问题是,对于给定的数据集和模型,这种关系是未知的,对于某些数据集和模型,这种关系可能不存在。此外,如果确实存在这种关系,可能会有一个或多个收益递减点,在这些点上,添加更多数据可能不会提高模型表现,或者数据集太小,无法有效捕获更大规模模型的能力。

这些问题可以通过执行灵敏度分析来量化数据集大小和模型表现之间的关系来解决。一旦计算出来,我们就可以解释分析的结果,并决定有多少数据是足够的,以及一个数据集可以有多小,以有效地估计较大数据集的表现。

在本教程中,您将了解如何对数据集大小和模型表现进行敏感性分析。

完成本教程后,您将知道:

  • 为机器学习选择数据集大小是一个具有挑战性的开放问题。
  • 对于给定的模型和预测问题,灵敏度分析提供了一种量化模型表现和数据集大小之间关系的方法。
  • 如何对数据集大小进行敏感性分析并解释结果。

我们开始吧。

Sensitivity Analysis of Dataset Size vs. Model Performance

数据集大小对模型表现的敏感性分析 图片由格雷姆·邱嘉德提供,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 数据集大小敏感性分析
  2. 综合预测任务和基线模型
  3. 数据集大小的敏感性分析

数据集大小敏感性分析

机器学习预测模型所需的训练数据量是一个未决问题。

这取决于您对模型的选择、准备数据的方式以及数据本身的细节。

有关选择训练数据集大小的挑战的更多信息,请参见教程:

解决这个问题的一种方法是执行灵敏度分析,并发现模型在数据集上的表现如何随数据的多少而变化。

这可能涉及用不同大小的数据集评估同一模型,并寻找数据集大小和表现之间的关系或收益递减点。

通常,训练数据集大小和模型表现之间有很强的关系,尤其是对于非线性模型。随着数据集大小的增加,这种关系通常会在某种程度上提高表现,并普遍降低模型的预期方差。

了解模型和数据集之间的这种关系可能会有所帮助,原因如下:

  • 评估更多模型。
  • 找一个更好的模型。
  • 决定收集更多的数据。

您可以在较小的数据集样本上快速评估大量模型和模型配置,确信表现可能会以特定方式推广到较大的训练数据集。

这可能允许评估比您在给定时间内能够评估的更多的模型和配置,并且反过来,可能发现更好的整体表现模型。

您还可以将模型表现的预期表现推广和估计到更大的数据集,并估计收集更多训练数据是否值得。

既然我们已经熟悉了执行模型表现对数据集大小的敏感性分析的想法,让我们来看一个工作示例。

综合预测任务和基线模型

在我们深入进行敏感性分析之前,让我们为调查选择一个数据集和基线模型。

在本教程中,我们将使用合成二进制(两类)分类数据集。这是理想的,因为它允许我们根据需要为相同的问题调整生成样本的数量。

make _ classification()sci kit-learn 功能可用于创建合成分类数据集。在这种情况下,我们将使用 20 个输入特征(列)并生成 1,000 个样本(行)。伪随机数生成器的种子是固定的,以确保每次生成样本时使用相同的基本“问题”。

下面的示例生成了合成分类数据集,并总结了生成数据的形状。

# test classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# summarize the dataset
print(X.shape, y.shape)

运行该示例会生成数据并报告输入和输出组件的大小,从而确认预期的形状。

(1000, 20) (1000,)

接下来,我们可以在这个数据集上评估一个预测模型。

我们将使用决策树(决策树分类器)作为预测模型。之所以选择它,是因为它是一种非线性算法,并且具有较高的方差,这意味着我们预计表现会随着训练数据集大小的增加而提高。

我们将使用重复分层 k 折叠交叉验证的最佳实践来评估数据集上的模型,重复 3 次,折叠 10 次。

下面列出了在综合分类数据集上评估决策树模型的完整示例。

# evaluate a decision tree model on the synthetic classification dataset
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.tree import DecisionTreeClassifier
# load dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# define model evaluation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# define model
model = DecisionTreeClassifier()
# evaluate model
scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# report performance
print('Mean Accuracy: %.3f (%.3f)' % (scores.mean(), scores.std()))

运行该示例会创建数据集,然后使用所选的测试工具来评估模型在问题上的表现。

:考虑到算法或评估程序的随机性,或数值精确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到平均分类准确率约为 82.7%。

Mean Accuracy: 0.827 (0.042)

接下来,让我们看看如何对数据集大小对模型表现进行敏感性分析。

数据集大小的敏感性分析

上一节展示了如何在可用数据集上评估所选模型。

这引起了一些问题,例如:

模型在更多数据上的表现会更好吗?

更一般地说,我们可能有复杂的问题,例如:

问题域中较小或较大样本的估计表现是否成立?

这些都是很难回答的问题,但是我们可以通过敏感性分析来解决。具体来说,我们可以通过敏感度分析来了解:

模型表现对数据集大小有多敏感?

或者更一般地说:

数据集大小与模型表现有什么关系?

执行敏感性分析的方法有很多,但最简单的方法可能是定义一个测试工具来评估模型表现,然后用不同大小的数据集在相同的问题上评估相同的模型。

这将允许数据集的训练和测试部分随着整个数据集的大小而增加。

为了使代码更容易阅读,我们将把它分成函数。

首先,我们可以定义一个函数来准备(或加载)给定大小的数据集。数据集中的行数由函数的参数指定。

如果您将此代码用作模板,则可以更改此函数以从文件中加载数据集,并选择给定大小的随机样本。

# load dataset
def load_dataset(n_samples):
	# define the dataset
	X, y = make_classification(n_samples=int(n_samples), n_features=20, n_informative=15, n_redundant=5, random_state=1)
	return X, y

接下来,我们需要一个函数来评估加载数据集上的模型。

我们将定义一个函数,该函数接受一个数据集,并返回使用数据集上的测试工具评估的模型表现的摘要。

下面列出了这个函数,它获取数据集的输入和输出元素,并返回数据集上决策树模型的平均值和标准差。

# evaluate a model
def evaluate_model(X, y):
	# define model evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# define model
	model = DecisionTreeClassifier()
	# evaluate model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	# return summary stats
	return [scores.mean(), scores.std()]

接下来,我们可以定义一系列不同的数据集大小来进行评估。

大小的选择应与您可用的数据量和您愿意花费的运行时间成比例。

在这种情况下,我们将保持适当的大小来限制运行时间,从 50 行到 100 万行,大致按 log10 的比例。

...
# define number of samples to consider
sizes = [50, 100, 500, 1000, 5000, 10000, 50000, 100000, 500000, 1000000]

接下来,我们可以枚举每个数据集的大小,创建数据集,评估数据集上的模型,并存储结果供以后分析。

...
# evaluate each number of samples
means, stds = list(), list()
for n_samples in sizes:
	# get a dataset
	X, y = load_dataset(n_samples)
	# evaluate a model on this dataset size
	mean, std = evaluate_model(X, y)
	# store
	means.append(mean)
	stds.append(std)

接下来,我们可以总结数据集大小和模型表现之间的关系。

在这种情况下,我们将简单地用误差线绘制结果,这样我们就可以直观地发现任何趋势。

我们将使用标准偏差作为估计模型表现不确定性的度量。如果表现遵循正态分布,这可以通过将该值乘以 2 以覆盖大约 95%的预期表现来实现。

这可以在图上显示为数据集大小的平均预期表现周围的误差线。

...
# define error bar as 2 standard deviations from the mean or 95%
err = [min(1, s * 2) for s in stds]
# plot dataset size vs mean performance with error bars
pyplot.errorbar(sizes, means, yerr=err, fmt='-o')

为了使图更易读,我们可以将 x 轴的比例改为 log,因为我们的数据集大小大约为 log10。

...
# change the scale of the x-axis to log
ax = pyplot.gca()
ax.set_xscale("log", nonpositive='clip')
# show the plot
pyplot.show()

就这样。

我们通常预期平均模型表现会随着数据集的大小而增加。我们还预计模型表现的不确定性会随着数据集的大小而降低。

将所有这些结合起来,下面列出了对数据集大小对模型表现进行敏感性分析的完整示例。

# sensitivity analysis of model performance to dataset size
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.tree import DecisionTreeClassifier
from matplotlib import pyplot

# load dataset
def load_dataset(n_samples):
	# define the dataset
	X, y = make_classification(n_samples=int(n_samples), n_features=20, n_informative=15, n_redundant=5, random_state=1)
	return X, y

# evaluate a model
def evaluate_model(X, y):
	# define model evaluation procedure
	cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
	# define model
	model = DecisionTreeClassifier()
	# evaluate model
	scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
	# return summary stats
	return [scores.mean(), scores.std()]

# define number of samples to consider
sizes = [50, 100, 500, 1000, 5000, 10000, 50000, 100000, 500000, 1000000]
# evaluate each number of samples
means, stds = list(), list()
for n_samples in sizes:
	# get a dataset
	X, y = load_dataset(n_samples)
	# evaluate a model on this dataset size
	mean, std = evaluate_model(X, y)
	# store
	means.append(mean)
	stds.append(std)
	# summarize performance
	print('>%d: %.3f (%.3f)' % (n_samples, mean, std))
# define error bar as 2 standard deviations from the mean or 95%
err = [min(1, s * 2) for s in stds]
# plot dataset size vs mean performance with error bars
pyplot.errorbar(sizes, means, yerr=err, fmt='-o')
# change the scale of the x-axis to log
ax = pyplot.gca()
ax.set_xscale("log", nonpositive='clip')
# show the plot
pyplot.show()

运行该示例会报告数据集大小和估计模型表现的状态。

:考虑到算法或评估程序的随机性,或数值精确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。

在这种情况下,我们可以看到平均模型表现随着数据集大小的增加而增加,而使用分类精确率的标准偏差测量的模型方差减少的预期趋势。

我们可以看到,在估计大约 10,000 或 50,000 行的模型表现时,可能存在收益递减点。

具体来说,我们确实看到行越多,表现越好,但我们可能可以捕捉到这种关系,与 10K 或 50K 行数据的差异很小。

我们还可以看到 1000000 行数据的估计表现下降,这表明我们可能在 100000 行以上最大化模型的能力,而是在估计中测量统计噪声。

这可能意味着预期表现有一个上限,超过这个上限的数据可能不会改善所选测试工具的特定模型和配置。

>50: 0.673 (0.141)
>100: 0.703 (0.135)
>500: 0.809 (0.055)
>1000: 0.826 (0.044)
>5000: 0.835 (0.016)
>10000: 0.866 (0.011)
>50000: 0.900 (0.005)
>100000: 0.912 (0.003)
>500000: 0.938 (0.001)
>1000000: 0.936 (0.001)

该图使数据集大小和估计模型表现之间的关系更加清晰。

这种关系几乎与日志数据集的大小成线性关系。误差线所示的不确定性的变化也在图上显著减少,从 50 或 100 个样本的非常大的值,到 5000 和 10000 个样本的中等值,实际上超过了这些大小。

考虑到 5,000 和 10,000 个样本的适度分布以及实际上的对数线性关系,我们可能可以使用 5K 或 10K 行来近似模型表现。

Line Plot With Error Bars of Dataset Size vs. Model Performance

数据集大小误差线与模型表现的线图

我们可以将这些发现作为测试其他模型配置甚至不同模型类型的基础。

危险在于,不同的模型在或多或少的数据下可能表现得非常不同,用不同的模型重复敏感性分析来确认关系成立可能是明智的。或者,用一套不同的模型类型重复分析可能会很有趣。

进一步阅读

如果您想更深入地了解这个主题,本节将提供更多资源。

教程

蜜蜂

文章

摘要

在本教程中,您发现了如何对数据集大小和模型表现进行敏感性分析。

具体来说,您了解到:

  • 为机器学习选择数据集大小是一个具有挑战性的开放问题。
  • 对于给定的模型和预测问题,灵敏度分析提供了一种量化模型表现和数据集大小之间关系的方法。
  • 如何对数据集大小进行敏感性分析并解释结果。

你有什么问题吗? 在下面的评论中提问,我会尽力回答。

如何使用 Anaconda 为机器学习和深度学习设置 Python 环境

原文: machinelearningmastery.com/setup-python-environment-machine-learning-deep-learning-anaconda/

在某些平台上安装 Python 机器学习环境可能很困难。

必须首先安装 Python 本身,然后安装许多软件包,这对初学者来说可能会造成混淆。

在本教程中,您将了解如何使用 Anaconda 设置 Python 机器学习开发环境。

完成本教程后,您将拥有一个可用的 Python 环境,可以开始学习,练习和开发机器学习和深度学习软件。

这些说明适用于 Windows,Mac OS X 和 Linux 平台。我将在 OS X 上演示它们,因此您可能会看到一些 mac 对话框和文件扩展名。

  • 2017 年 3 月更新:补充说明你只需要 Theano 或 TensorFlow 中的一个来使用 Kears 进行深度学习。

How to Setup a Python Environment for Machine Learning and Deep Learning with Anaconda

如何使用 Anaconda 为机器学习和深度学习设置 Python 环境

概观

在本教程中,我们将介绍以下步骤:

  1. 下载 Anaconda
  2. 安装 Anaconda
  3. 启动并更新 Anaconda
  4. 更新 scikit-learn Library
  5. 安装深度学习库

1.下载 Anaconda

在此步骤中,我们将为您的平台下载 Anaconda Python 软件包。

Anaconda 是一个免费且易于使用的科学 Python 环境。

Click Anaconda and Download

单击 Anaconda 和下载

  • 3.选择适合您平台的下载(Windows,OSX 或 Linux):
    • 选择 Python 3.5
    • 选择图形安装程序

Choose Anaconda Download for Your Platform

为您的平台选择 Anaconda 下载

这会将 Anaconda Python 软件包下载到您的工作站。

我在 OS X 上,所以我选择了 OS X 版本。该文件大约 426 MB。

你应该有一个名称如下的文件:

Anaconda3-4.2.0-MacOSX-x86_64.pkg

2.安装 Anaconda

在此步骤中,我们将在您的系统上安装 Anaconda Python 软件。

此步骤假定您具有足够的管理权限以在系统上安装软件。

  • 1.双击下载的文件。
  • 2.按照安装向导进行操作。

Anaconda Python Installation Wizard

Anaconda Python 安装向导

安装快速无痛。

应该没有棘手的问题或难点。

Anaconda Python Installation Wizard Writing files

Anaconda Python 安装向导编写文件

安装应该不到 10 分钟,并占用硬盘驱动器上 1 GB 以上的空间。

3.启动并更新 Anaconda

在此步骤中,我们将确认您的 Anaconda Python 环境是最新的。

Anaconda 附带一套名为 Anaconda Navigator 的图形工具。您可以从应用程序启动器中打开 Anaconda Navigator。

Anaconda Navigator GUI

Anaconda Navigator GUI

您可以在这里了解 Anaconda Navigator 的所有信息。

您可以稍后使用 Anaconda Navigator 和图形开发环境;现在,我建议从名为 conda 的 Anaconda 命令行环境开始。

Conda 快速,简单,隐藏错误消息很难,您可以快速确认您的环境已安装并正常工作。

  • 1.打开终端(命令行窗口)。
  • 2.输入以下命令确认 conda 已正确安装:
conda -V

你应该看到以下(或类似的东西):

conda 4.2.9
  • 3.键入以下命令确认 Python 已正确安装:
python -V

You should see the following (or something similar):

Python 3.5.2 :: Anaconda 4.2.0 (x86_64)

Confirm Conda and Python are Installed

确认已安装 Conda 和 Python

如果命令不起作用或出现错误,请查看文档以获取适用于您的平台的帮助。

请参阅“进一步阅读”部分中的一些资源。

  • 4.确认您的 conda 环境是最新的,键入:
conda update conda
conda update anaconda

您可能需要安装一些软件包并确认更新。

  • 5.确认您的 SciPy 环境。

下面的脚本将打印机器学习开发所需的关键 SciPy 库的版本号,特别是:SciPy,NumPy,Matplotlib,Pandas,Statsmodels 和 Scikit-learn。

您可以键入“python”并直接键入命令。或者,我建议打开文本编辑器并将脚本复制粘贴到编辑器中。

# scipy
import scipy
print('scipy: %s' % scipy.__version__)
# numpy
import numpy
print('numpy: %s' % numpy.__version__)
# matplotlib
import matplotlib
print('matplotlib: %s' % matplotlib.__version__)
# pandas
import pandas
print('pandas: %s' % pandas.__version__)
# statsmodels
import statsmodels
print('statsmodels: %s' % statsmodels.__version__)
# scikit-learn
import sklearn
print('sklearn: %s' % sklearn.__version__)

将脚本保存为名为versions.py的文件。

在命令行上,将目录更改为保存脚本的位置并键入:

python versions.py

您应该看到如下输出:

scipy: 0.18.1
numpy: 1.11.1
matplotlib: 1.5.3
pandas: 0.18.1
statsmodels: 0.6.1
sklearn: 0.17.1

你得到了什么版本? 将输出粘贴到下面的注释中。

Confirm Anaconda SciPy environment

确认 Anaconda SciPy 环境

4.更新 scikit-learn Library

在这一步中,我们将更新用于 Python 机器学习的主库,名为 scikit-learn。

  • 1.更新 scikit-学习最新版本。

在撰写本文时,Anaconda 附带的 scikit-learn 版本已过时(0.17.1 而不是 0.18.1)。您可以使用 conda 命令更新特定库;下面是更新 scikit-learn 到最新版本的示例。

在终端输入:

conda update scikit-learn

Update scikit-learn in Anaconda

更新 Anikonda 中的 scikit-learn

或者,您可以通过键入以下内容将库更新为特定版本:

conda install -c anaconda scikit-learn=0.18.1

确认安装成功并通过键入以下命令重新运行versions.py脚本来更新 scikit-learn:

python versions.py

You should see output like the following:

scipy: 0.18.1
numpy: 1.11.3
matplotlib: 1.5.3
pandas: 0.18.1
statsmodels: 0.6.1
sklearn: 0.18.1

What versions did you get? Paste the output in the comments below.

您可以根据需要使用这些命令更新机器学习和 SciPy 库。

尝试 scikit-learn 教程,例如:

5.安装深度学习库

在这一步中,我们将安装用于深度学习的 Python 库,特别是:Theano,TensorFlow 和 Keras。

:我建议使用 Keras 进行深度学习,而 Keras 只需要安装 Theano 或 TensorFlow 中的一个。你不需要两个!在某些 Windows 计算机上安装 TensorFlow 可能会出现问题。

  • 1.输入以下命令安装 Theano 深度学习库:
conda install theano
  • 2.键入以下命令安装 TensorFlow 深度学习库(Windows 以外的所有库):
conda install -c conda-forge tensorflow

或者,您可以选择使用 pip 和特定版本的 tensorflow 为您的平台安装。

有关张量流,请参阅安装说明。

  • 3.输入以下命令安装 Keras:
pip install keras
  • 4.确认您的深度学习环境已安装并正常运行。

创建一个打印每个库的版本号的脚本,就像我们之前为 SciPy 环境所做的那样。

# theano
import theano
print('theano: %s' % theano.__version__)
# tensorflow
import tensorflow
print('tensorflow: %s' % tensorflow.__version__)
# keras
import keras
print('keras: %s' % keras.__version__)

将脚本保存到文件deep_versions.py。键入以下命令运行脚本:

python deep_versions.py

您应该看到如下输出:

theano: 0.8.2.dev-901275534cbfe3fbbe290ce85d1abf8bb9a5b203
tensorflow: 0.12.1
Using TensorFlow backend.
keras: 1.2.1

Anaconda Confirm Deep Learning Libraries

Anaconda 确认深度学习库

你得到了什么版本? 将您的输出粘贴到下面的注释中。

尝试使用 Keras 深度学习教程,例如:

进一步阅读

本节提供了一些进一步阅读的链接。

摘要

恭喜,您现在拥有一个可用于机器学习和深度学习的 Python 开发环境。

您现在可以在工作站上学习和练习机器学习和深度学习。

你是怎么去的? 请在下面的评论中告诉我。

使用 Python 和 scikit-learn 采样检查分类机器学习算法

原文: machinelearningmastery.com/spot-check-classification-machine-learning-algorithms-python-scikit-learn/

采样检查是一种发现哪些算法在您的机器学习问题上表现良好的方法。

您无法预先知道哪种算法最适合您的问题。你必须尝试一些方法,并将注意力集中在那些证明自己最有希望的方法上。

在这篇文章中,您将发现 6 种机器学习算法,您可以在使用 scikit-learn 在 Python 中检查分类问题时使用这些算法。

让我们开始吧。

  • 2017 年 1 月更新:已更新,以反映版本 0.18 中 scikit-learn API 的更改。
  • 更新 March / 2018 :添加了备用链接以下载数据集,因为原始图像已被删除。

Spot-Check Classification Machine Learning Algorithms in Python with scikit-learn

用 scikit-learn 照片分析机器学习算法 Masahiro Ihara ,保留一些权利

算法现场检查

您无法预先知道哪种算法最适合您的数据集。

您必须使用反复试验来发现一个简短的算法列表,这些算法可以很好地解决您的问题,然后您可以加倍并进一步调整。我称这个过程现场检查。

问题不是:

我应该在数据集上使用什么算法?

相反,它是:

我应该在哪些算法上检查我的数据集?

您可以猜测哪些算法可能对您的数据集做得很好,这可能是一个很好的起点。

我建议尝试混合使用算法,看看哪种方法能够很好地选择数据中的结构。

  • 尝试混合算法表示(例如实例和树)。
  • 尝试混合使用学习算法(例如,学习相同类型的表示的不同算法)。
  • 尝试混合使用建模类型(例如线性和非线性函数或参数和非参数)。

让我们具体一点。在下一节中,我们将介绍可用于在 Python 中检查下一个机器学习项目的算法。

算法概述

我们将看一下您可以检查数据集的 6 种分类算法。

2 线性机器学习算法:

  1. 逻辑回归
  2. 线性判别分析

4 种非线性机器学习算法:

  1. K 最近邻
  2. 朴素贝叶斯
  3. 分类和回归树
  4. 支持向量机

每个秘籍都在皮马印第安人糖尿病数据集上发表(更新:从这里下载)。这是一个二分类问题,其中所有属性都是数字。

每个秘籍都是完整且独立的。这意味着您可以将其复制并粘贴到您自己的项目中并立即开始使用它。

使用 10 倍交叉验证的测试工具用于演示如何检查每个机器学习算法,并且使用平均准确度测量来指示算法表现。

这些秘籍假设您了解每种机器学习算法以及如何使用它们。我们不会进入每个算法的 API 或参数化。

线性机器学习算法

本节演示了如何使用两种线性机器学习算法的最小秘籍:逻辑回归和线性判别分析。

1. 逻辑回归

逻辑回归假定数值输入变量的高斯分布,并且可以模拟二分类问题。

您可以使用 LogisticRegression 类构建逻辑回归模型。

# Logistic Regression Classification
import pandas
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LogisticRegression()
results = model_selection.cross_val_score(model, X, Y, cv=kfold)
print(results.mean())

运行该示例打印平均估计精度。

0.76951469583

2.线性判别分析

线性判别分析或 LDA 是用于二元和多分类的统计技术。它也假定数值输入变量的高斯分布。

您可以使用 LinearDiscriminantAnalysis 类构建 LDA 模型。

# LDA Classification
import pandas
from sklearn import model_selection
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = LinearDiscriminantAnalysis()
results = model_selection.cross_val_score(model, X, Y, cv=kfold)
print(results.mean())

Running the example prints the mean estimated accuracy.

0.773462064252

非线性机器学习算法

本节演示了如何使用 4 种非线性机器学习算法的最小秘籍。

1. K 最近邻

K 最近邻(或 KNN)使用距离度量来查找新实例的训练数据中的 K 个最相似的实例,并将邻居的平均结果作为预测。

您可以使用 KNeighborsClassifier 类构建 KNN 模型。

# KNN Classification
import pandas
from sklearn import model_selection
from sklearn.neighbors import KNeighborsClassifier
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
random_state = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = KNeighborsClassifier()
results = model_selection.cross_val_score(model, X, Y, cv=kfold)
print(results.mean())

Running the example prints the mean estimated accuracy.

0.726555023923

2.朴素的贝叶斯

朴素贝叶斯计算每个类的概率以及给定每个输入值的每个类的条件概率。假设它们都是独立的(简单或朴素的假设),对新数据估计这些概率并相乘。

当使用实值数据时,假设高斯分布使用高斯概率密度函数容易地估计输入变量的概率。

您可以使用 GaussianNB 类构建朴素贝叶斯模型。

# Gaussian Naive Bayes Classification
import pandas
from sklearn import model_selection
from sklearn.naive_bayes import GaussianNB
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = GaussianNB()
results = model_selection.cross_val_score(model, X, Y, cv=kfold)
print(results.mean())

Running the example prints the mean estimated accuracy.

0.75517771702

3.分类和回归树

分类和回归树(CART 或仅决策树)根据训练数据构造二叉树。通过评估训练数据中每个属性和每个属性的每个值来贪婪地选择分裂点,以便最小化成本函数(如 Gini )。

您可以使用 DecisionTreeClassifier 类构建 CART 模型。

# CART Classification
import pandas
from sklearn import model_selection
from sklearn.tree import DecisionTreeClassifier
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = DecisionTreeClassifier()
results = model_selection.cross_val_score(model, X, Y, cv=kfold)
print(results.mean())

Running the example prints the mean estimated accuracy.

0.692600820232

4.支持向量机

支持向量机(或 SVM)寻求最佳分隔两个类的行。那些最接近最佳分隔类的行的数据实例称为支持向量,并影响放置行的位置。 SVM 已扩展为支持多个类。

特别重要的是通过内核参数使用不同的内核函数。默认情况下使用功能强大的径向基函数

您可以使用 SVC 类构建 SVM 模型。

# SVM Classification
import pandas
from sklearn import model_selection
from sklearn.svm import SVC
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
seed = 7
kfold = model_selection.KFold(n_splits=10, random_state=seed)
model = SVC()
results = model_selection.cross_val_score(model, X, Y, cv=kfold)
print(results.mean())

Running the example prints the mean estimated accuracy.

0.651025290499

摘要

在这篇文章中,您发现了 6 种机器学习算法,您可以使用 scikit-learn 在 Python 中对您的分类问题进行采样检查。

具体来说,您学会了如何进行抽查:

2 线性机器学习算法

  1. 逻辑回归
  2. 线性判别分析

4 种非线性机器学习算法

  1. K 最近邻
  2. 朴素贝叶斯
  3. 分类和回归树
  4. 支持向量机

您对现场检查机器学习算法或此帖子有任何疑问吗?在下面的评论部分提出您的问题,我会尽力回答。

如何在 Python 中开发可重复使用的采样检查算法框架

译文: machinelearningmastery.com/spot-check-machine-learning-algorithms-in-python/

采样检查算法是一种应用机器学习技术,旨在快速客观地为新的预测性建模问题提供第一组结果。

与寻找算法的最佳算法或最佳配置的网格搜索和其他类型的算法调整不同,点检查旨在快速评估各种算法并提供粗略的第一切结果。如果问题或问题表示确实是可预测的,则可以使用该第一剪切结果,如果是,则可能值得进一步研究该问题的算法类型。

现场检查是一种帮助克服应用机器学习的“难题”的方法,并鼓励您清楚地考虑在任何机器学习项目中执行的高阶搜索问题

在本教程中,您将发现现场检查算法对新预测性建模问题的有用性,以及如何在 python 中为分类和回归问题开发用于采样检查算法的标准框架。

完成本教程后,您将了解:

  • 采样检查提供了一种快速发现在预测性建模问题上表现良好的算法类型的方法。
  • 如何开发用于加载数据,定义模型,评估模型和总结结果的通用框架。
  • 如何应用框架进行分类和回归问题。

让我们开始吧。

How to Develop a Reusable Framework for Spot-Check Algorithms in Python

如何在 Python 中开发可重复使用的采样检查算法框架 Jeff Turner 的照片,保留一些权利。

教程概述

本教程分为五个部分;他们是:

  1. 采样检查算法
  2. Python 中的 Spot-Checking 框架
  3. 现场检查分类
  4. 现场检查回归
  5. 框架扩展

1.采样检查算法

我们事先无法知道哪些算法在给定的预测性建模问题上表现良好。

这是应用机器学习的难点部分,只能通过系统实验来解决。

抽查是解决这个问题的方法。

它涉及针对问题快速测试大量不同的机器学习算法,以便快速发现哪些算法可能起作用以及在哪里集中注意力。

  • 速度很快;它绕过准备和分析的几天或几周,并使用可能不会导致结果的算法。
  • 它是客观的,允许您发现什么可能适用于问题,而不是使用您上次使用的。
  • 得到结果;您将实际拟合模型,做出预测并了解您的问题是否可以预测以及基线技能可能是什么样子。

采样检查可能需要您使用数据集的一小部分样本才能快速转换结果。

最后,现场检查的结果是一个起点。一个起点。他们建议将注意力集中在问题上,而不是最佳算法。该过程旨在让您摆脱典型的思考和分析,转而关注结果。

您可以在帖子中了解有关抽查的更多信息:

现在我们知道了什么是现场检查,让我们看看如何在 Python 中系统地执行采样检查。

2. Python 中的 Spot-Checking 框架

在本节中,我们将构建一个脚本框架,该框架可用于在分类或回归问题上对机器学习算法进行采样检查。

我们需要开发框架有四个部分;他们是:

  • 加载数据集
  • 定义模型
  • 评估模型
  • 总结结果

让我们依次看看每一个。

加载数据集

框架的第一步是加载数据。

必须针对给定问题实现该功能,并专门针对该问题。它可能涉及从一个或多个 CSV 文件加载数据。

我们将调用此函数 load_data();它不需要参数并返回输入(X)和输出(y)用于预测问题。

# load the dataset, returns X and y elements
def load_dataset():
	X, y = None, None
	return X, y

定义模型

下一步是定义模型以评估预测性建模问题。

定义的模型将特定于类型预测性建模问题,例如,分类或回归。

定义的模型应该是多样的,包括以下的混合:

  • 线性模型。
  • 非线性模型。
  • 合奏模型。

每个模型应该是一个很好的机会,可以很好地解决问题。这可能意味着提供模型的一些变体,使用不同的常见或众所周知的配置,平均表现良好。

我们将调用此函数 define_models()。它将返回映射到 scikit-learn 模型对象的模型名称字典。名称应该很短,例如'svm',并且可以包括配置细节,例如“KNN-7”。

该函数还将字典作为可选参数;如果未提供,则创建并填充新字典。如果提供了字典,则会向其添加模型。

如果您希望使用多个函数来定义模型,或者添加具有不同配置的特定类型的大量模型,则可以增加灵活性。

# create a dict of standard models to evaluate {name:object}
def define_models(models=dict()):
	# ...
	return models

我们的想法不是网格搜索模型参数;那可以晚点来。

相反,每个模型应该有机会表现良好(即不是最佳)。这可能意味着在某些情况下尝试许多参数组合,例如在梯度增强的情况下。

评估模型

下一步是评估已加载数据集上的已定义模型。

scikit-learn 库提供了在评估期间管道模型的能力。这允许在用于拟合模型之前变换数据,并且这以正确的方式完成,使得变换在训练数据上准备并应用于测试数据。

我们可以定义一个函数,在评估之前准备给定的模型,以允许在采样检查过程中使用特定的变换。它们将以一揽子方式对所有模型进行。这对于执行标准化,规范化和特征选择等操作非常有用。

我们将定义一个名为make_pipeline()的函数,它接受一个已定义的模型并返回一个管道。下面是准备管道的示例,该管道将首先标准化输入数据,然后在拟合模型之前对其进行标准化。

# create a feature preparation pipeline for a model
def make_pipeline(model):
	steps = list()
	# standardization
	steps.append(('standardize', StandardScaler()))
	# normalization
	steps.append(('normalize', MinMaxScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

此函数可以扩展为添加其他变换,或者简化为返回提供的模型而不进行变换。

现在我们需要评估准备好的模型。

我们将使用 k-fold 交叉验证评估模型的标准。对每个定义的模型的评估将产生结果列表。这是因为该模型的 10 个不同版本将被拟合和评估,从而得到 k 分数列表。

我们将定义一个名为evaluate_model()的函数,该函数将获取数据,定义的模型,多个折叠以及用于评估结果的表现指标。它将返回分数列表。

该函数调用make_pipeline()为定义的模型准备所需的任何数据变换,然后调用 cross_val_score() scikit-learn 函数。重要的是,n_jobs参数设置为-1,以允许模型评估并行发生,从而利用硬件上可用的核心数量。

# evaluate a single model
def evaluate_model(X, y, model, folds, metric):
	# create the pipeline
	pipeline = make_pipeline(model)
	# evaluate model
	scores = cross_val_score(pipeline, X, y, scoring=metric, cv=folds, n_jobs=-1)
	return scores

模型的评估可能会因异常而失败。我已经看到了这一点,特别是在 statsmodels 库中的一些模型的情况下。

评估模型也可能产生大量警告信息。我已经看到了这一点,特别是在使用 XGBoost 模型的情况下。

在抽查时我们不关心异常或警告。我们只想知道哪些有效,哪些有效。因此,我们可以在评估每个模型时捕获异常并忽略所有警告。

名为robust_evaluate_model()的函数实现了此行为。evaluate_model()的调用方式是捕获异常并忽略警告。如果发生异常并且给定模型无法得到结果,则返回 _ 无 _ 结果。

# evaluate a model and try to trap errors and and hide warnings
def robust_evaluate_model(X, y, model, folds, metric):
	scores = None
	try:
		with warnings.catch_warnings():
			warnings.filterwarnings("ignore")
			scores = evaluate_model(X, y, model, folds, metric)
	except:
		scores = None
	return scores

最后,我们可以定义顶级函数来评估已定义模型的列表。

我们将定义一个名为evaluate_models()的函数,它将模型字典作为参数,并将模型名称字典返回到结果列表。

交叉验证过程中的折叠数可以由默认为 10 的可选参数指定。根据模型的预测计算的度量也可以由可选参数指定,默认为分类精度。

有关支持的指标的完整列表,请参阅此列表:

跳过任何无结果,不会将其添加到结果字典中。

重要的是,我们提供了一些详细的输出,总结了每个模型评估后的平均值和标准差。如果数据集上的采样检查过程需要几分钟到几小时,这将非常有用。

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(X, y, models, folds=10, metric='accuracy'):
	results = dict()
	for name, model in models.items():
		# evaluate the model
		scores = robust_evaluate_model(X, y, model, folds, metric)
		# show process
		if scores is not None:
			# store a result
			results[name] = scores
			mean_score, std_score = mean(scores), std(scores)
			print('>%s: %.3f (+/-%.3f)' % (name, mean_score, std_score))
		else:
			print('>%s: error' % name)
	return results

请注意,如果由于某种原因您想要查看警告和错误,您可以更新evaluate_models()以直接调用evaluate_model()函数,绕过强大的错误处理。在测试静默失败的新方法或方法配置时,我发现这很有用。

总结结果

最后,我们可以评估结果。

真的,我们只想知道哪些算法表现良好。

总结结果的两种有用方法是:

  1. 排名前 10 位的算法的平均值和标准差的线摘要。
  2. 前 10 名执行算法的框和胡须图。

线条摘要快速而精确,但假设表现良好的高斯分布,这可能不合理。

盒子和须状图假设没有分布,并提供了一种直观的方法,可以直接比较模型的分数在中位数表现和分数差异方面的分布。

我们将定义一个名为summarize_results()的函数,该函数获取结果字典,打印结果摘要,并创建保存到文件的 boxplot 图像。该函数接受一个参数来指定评估得分是否最大化,默认情况下为True。要汇总的结果数也可以作为可选参数提供,默认为 10。

该功能首先在打印摘要和创建框和须图之前对得分进行排序。

# print and plot the top n results
def summarize_results(results, maximize=True, top_n=10):
	# check for no results
	if len(results) == 0:
		print('no results')
		return
	# determine how many results to summarize
	n = min(top_n, len(results))
	# create a list of (name, mean(scores)) tuples
	mean_scores = [(k,mean(v)) for k,v in results.items()]
	# sort tuples by mean score
	mean_scores = sorted(mean_scores, key=lambda x: x[1])
	# reverse for descending order (e.g. for accuracy)
	if maximize:
		mean_scores = list(reversed(mean_scores))
	# retrieve the top n for summarization
	names = [x[0] for x in mean_scores[:n]]
	scores = [results[x[0]] for x in mean_scores[:n]]
	# print the top n
	print()
	for i in range(n):
		name = names[i]
		mean_score, std_score = mean(results[name]), std(results[name])
		print('Rank=%d, Name=%s, Score=%.3f (+/- %.3f)' % (i+1, name, mean_score, std_score))
	# boxplot for the top n
	pyplot.boxplot(scores, labels=names)
	_, labels = pyplot.xticks()
	pyplot.setp(labels, rotation=90)
	pyplot.savefig('spotcheck.png')

现在我们已经专门设计了一个用于 Python 中的采样算法的框架,让我们看一下如何将它应用于分类问题。

3.现场检查分类

我们将使用 make_classification()函数生成二分类问题。

该函数将生成 1,000 个样本,包含 20 个变量,一些冗余变量和两个类。

# load the dataset, returns X and y elements
def load_dataset():
	return make_classification(n_samples=1000, n_classes=2, random_state=1)

作为分类问题,我们将尝试一套分类算法,具体来说:

线性算法

  • 逻辑回归
  • 岭回归
  • 随机梯度下降分类器
  • 被动攻击性分类器

我尝试了 LDA 和 QDA,但他们遗憾地在某处的 C 代码中崩溃了。

非线性算法

  • k-最近邻居
  • 分类和回归树
  • 额外的树
  • 支持向量机
  • 朴素贝叶斯

集成算法

  • AdaBoost 的
  • 袋装决策树
  • 随机森林
  • 额外的树木
  • 梯度增压机

此外,我为一些算法添加了多种配置,如 Ridge,kNN 和 SVM,以便为他们提供很好的解决问题的机会。

下面列出了完整的define_models()函数。

# create a dict of standard models to evaluate {name:object}
def define_models(models=dict()):
	# linear models
	models['logistic'] = LogisticRegression()
	alpha = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for a in alpha:
		models['ridge-'+str(a)] = RidgeClassifier(alpha=a)
	models['sgd'] = SGDClassifier(max_iter=1000, tol=1e-3)
	models['pa'] = PassiveAggressiveClassifier(max_iter=1000, tol=1e-3)
	# non-linear models
	n_neighbors = range(1, 21)
	for k in n_neighbors:
		models['knn-'+str(k)] = KNeighborsClassifier(n_neighbors=k)
	models['cart'] = DecisionTreeClassifier()
	models['extra'] = ExtraTreeClassifier()
	models['svml'] = SVC(kernel='linear')
	models['svmp'] = SVC(kernel='poly')
	c_values = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for c in c_values:
		models['svmr'+str(c)] = SVC(C=c)
	models['bayes'] = GaussianNB()
	# ensemble models
	n_trees = 100
	models['ada'] = AdaBoostClassifier(n_estimators=n_trees)
	models['bag'] = BaggingClassifier(n_estimators=n_trees)
	models['rf'] = RandomForestClassifier(n_estimators=n_trees)
	models['et'] = ExtraTreesClassifier(n_estimators=n_trees)
	models['gbm'] = GradientBoostingClassifier(n_estimators=n_trees)
	print('Defined %d models' % len(models))
	return models

而已;我们现在准备好检查问题的算法。

下面列出了完整的示例。

# binary classification spot check script
import warnings
from numpy import mean
from numpy import std
from matplotlib import pyplot
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import RidgeClassifier
from sklearn.linear_model import SGDClassifier
from sklearn.linear_model import PassiveAggressiveClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import ExtraTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier

# load the dataset, returns X and y elements
def load_dataset():
	return make_classification(n_samples=1000, n_classes=2, random_state=1)

# create a dict of standard models to evaluate {name:object}
def define_models(models=dict()):
	# linear models
	models['logistic'] = LogisticRegression()
	alpha = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for a in alpha:
		models['ridge-'+str(a)] = RidgeClassifier(alpha=a)
	models['sgd'] = SGDClassifier(max_iter=1000, tol=1e-3)
	models['pa'] = PassiveAggressiveClassifier(max_iter=1000, tol=1e-3)
	# non-linear models
	n_neighbors = range(1, 21)
	for k in n_neighbors:
		models['knn-'+str(k)] = KNeighborsClassifier(n_neighbors=k)
	models['cart'] = DecisionTreeClassifier()
	models['extra'] = ExtraTreeClassifier()
	models['svml'] = SVC(kernel='linear')
	models['svmp'] = SVC(kernel='poly')
	c_values = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for c in c_values:
		models['svmr'+str(c)] = SVC(C=c)
	models['bayes'] = GaussianNB()
	# ensemble models
	n_trees = 100
	models['ada'] = AdaBoostClassifier(n_estimators=n_trees)
	models['bag'] = BaggingClassifier(n_estimators=n_trees)
	models['rf'] = RandomForestClassifier(n_estimators=n_trees)
	models['et'] = ExtraTreesClassifier(n_estimators=n_trees)
	models['gbm'] = GradientBoostingClassifier(n_estimators=n_trees)
	print('Defined %d models' % len(models))
	return models

# create a feature preparation pipeline for a model
def make_pipeline(model):
	steps = list()
	# standardization
	steps.append(('standardize', StandardScaler()))
	# normalization
	steps.append(('normalize', MinMaxScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

# evaluate a single model
def evaluate_model(X, y, model, folds, metric):
	# create the pipeline
	pipeline = make_pipeline(model)
	# evaluate model
	scores = cross_val_score(pipeline, X, y, scoring=metric, cv=folds, n_jobs=-1)
	return scores

# evaluate a model and try to trap errors and and hide warnings
def robust_evaluate_model(X, y, model, folds, metric):
	scores = None
	try:
		with warnings.catch_warnings():
			warnings.filterwarnings("ignore")
			scores = evaluate_model(X, y, model, folds, metric)
	except:
		scores = None
	return scores

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(X, y, models, folds=10, metric='accuracy'):
	results = dict()
	for name, model in models.items():
		# evaluate the model
		scores = robust_evaluate_model(X, y, model, folds, metric)
		# show process
		if scores is not None:
			# store a result
			results[name] = scores
			mean_score, std_score = mean(scores), std(scores)
			print('>%s: %.3f (+/-%.3f)' % (name, mean_score, std_score))
		else:
			print('>%s: error' % name)
	return results

# print and plot the top n results
def summarize_results(results, maximize=True, top_n=10):
	# check for no results
	if len(results) == 0:
		print('no results')
		return
	# determine how many results to summarize
	n = min(top_n, len(results))
	# create a list of (name, mean(scores)) tuples
	mean_scores = [(k,mean(v)) for k,v in results.items()]
	# sort tuples by mean score
	mean_scores = sorted(mean_scores, key=lambda x: x[1])
	# reverse for descending order (e.g. for accuracy)
	if maximize:
		mean_scores = list(reversed(mean_scores))
	# retrieve the top n for summarization
	names = [x[0] for x in mean_scores[:n]]
	scores = [results[x[0]] for x in mean_scores[:n]]
	# print the top n
	print()
	for i in range(n):
		name = names[i]
		mean_score, std_score = mean(results[name]), std(results[name])
		print('Rank=%d, Name=%s, Score=%.3f (+/- %.3f)' % (i+1, name, mean_score, std_score))
	# boxplot for the top n
	pyplot.boxplot(scores, labels=names)
	_, labels = pyplot.xticks()
	pyplot.setp(labels, rotation=90)
	pyplot.savefig('spotcheck.png')

# load dataset
X, y = load_dataset()
# get model list
models = define_models()
# evaluate models
results = evaluate_models(X, y, models)
# summarize results
summarize_results(results)

运行该示例为每个评估模型打印一行,结束对问题的前 10 个执行算法的摘要。

我们可以看到决策树的集合对这个问题表现最好。这表明了一些事情:

  • 决策树的集合可能是集中注意力的好地方。
  • 如果进一步调整,梯度提升可能会很好。
  • 该问题的“良好”表现是准确度约为 86%。
  • 岭回归的相对较高的表现表明需要进行特征选择。
...
>bag: 0.862 (+/-0.034)
>rf: 0.865 (+/-0.033)
>et: 0.858 (+/-0.035)
>gbm: 0.867 (+/-0.044)

Rank=1, Name=gbm, Score=0.867 (+/- 0.044)
Rank=2, Name=rf, Score=0.865 (+/- 0.033)
Rank=3, Name=bag, Score=0.862 (+/- 0.034)
Rank=4, Name=et, Score=0.858 (+/- 0.035)
Rank=5, Name=ada, Score=0.850 (+/- 0.035)
Rank=6, Name=ridge-0.9, Score=0.848 (+/- 0.038)
Rank=7, Name=ridge-0.8, Score=0.848 (+/- 0.038)
Rank=8, Name=ridge-0.7, Score=0.848 (+/- 0.038)
Rank=9, Name=ridge-0.6, Score=0.848 (+/- 0.038)
Rank=10, Name=ridge-0.5, Score=0.848 (+/- 0.038)

还创建了一个盒子和胡须图,以总结前 10 个表现良好的算法的结果。

该图显示了由决策树集合组成的方法的高程。该情节强调了进一步关注这些方法将是个好主意的观念。

Boxplot of top 10 Spot-Checking Algorithms on a Classification Problem

分类问题前 10 个采样检验算法的箱线图

如果这是一个真正的分类问题,我会跟进进一步的抽查,例如:

  • 使用各种不同的特征选择方法进行抽查。
  • 无需数据缩放方法的抽查。
  • 使用 sklearn 或 XGBoost 中的梯度增强配置的课程网格进行抽查。

接下来,我们将看到如何将框架应用于回归问题。

4.现场检查回归

我们可以通过非常小的变化来探索回归预测性建模问题的相同框架。

我们可以使用 make_regression()函数来生成一个人为的回归问题,包括 1,000 个示例和 50 个特征,其中一些是冗余的。

定义的load_dataset()功能如下所示。

# load the dataset, returns X and y elements
def load_dataset():
	return make_regression(n_samples=1000, n_features=50, noise=0.1, random_state=1)

然后我们可以指定一个get_models()函数来定义一套回归方法。

Scikit-learn 提供了广泛的线性回归方法,非常出色。并非所有这些都可能是您的问题所必需的。我建议使用最小的线性回归和弹性网,后者有一套很好的 alpha 和 lambda 参数。

不过,我们将测试有关此问题的全套方法,包括:

Linear Algorithms

  • 线性回归
  • 套索回归
  • 岭回归
  • 弹性网络回归
  • 胡贝尔回归
  • LARS 回归
  • Lasso LARS 回归
  • 被动攻击性回归
  • RANSAC 回归量
  • 随机梯度下降回归
  • Theil 回归

Nonlinear Algorithms

  • k-最近邻居
  • 分类和回归树
  • 额外的树
  • 支持向量回归

Ensemble Algorithms

  • AdaBoost 的
  • 袋装决策树
  • 随机森林
  • 额外的树木
  • 梯度增压机

完整的get_models()功能如下所示。

# create a dict of standard models to evaluate {name:object}
def get_models(models=dict()):
	# linear models
	models['lr'] = LinearRegression()
	alpha = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for a in alpha:
		models['lasso-'+str(a)] = Lasso(alpha=a)
	for a in alpha:
		models['ridge-'+str(a)] = Ridge(alpha=a)
	for a1 in alpha:
		for a2 in alpha:
			name = 'en-' + str(a1) + '-' + str(a2)
			models[name] = ElasticNet(a1, a2)
	models['huber'] = HuberRegressor()
	models['lars'] = Lars()
	models['llars'] = LassoLars()
	models['pa'] = PassiveAggressiveRegressor(max_iter=1000, tol=1e-3)
	models['ranscac'] = RANSACRegressor()
	models['sgd'] = SGDRegressor(max_iter=1000, tol=1e-3)
	models['theil'] = TheilSenRegressor()
	# non-linear models
	n_neighbors = range(1, 21)
	for k in n_neighbors:
		models['knn-'+str(k)] = KNeighborsRegressor(n_neighbors=k)
	models['cart'] = DecisionTreeRegressor()
	models['extra'] = ExtraTreeRegressor()
	models['svml'] = SVR(kernel='linear')
	models['svmp'] = SVR(kernel='poly')
	c_values = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for c in c_values:
		models['svmr'+str(c)] = SVR(C=c)
	# ensemble models
	n_trees = 100
	models['ada'] = AdaBoostRegressor(n_estimators=n_trees)
	models['bag'] = BaggingRegressor(n_estimators=n_trees)
	models['rf'] = RandomForestRegressor(n_estimators=n_trees)
	models['et'] = ExtraTreesRegressor(n_estimators=n_trees)
	models['gbm'] = GradientBoostingRegressor(n_estimators=n_trees)
	print('Defined %d models' % len(models))
	return models

默认情况下,框架使用分类准确率作为评估模型预测的方法。

这对回归没有意义,我们可以改变这对回归更有意义的东西,例如均方误差。我们可以通过在调用evaluate_models()函数时传递 metric ='neg_mean_squared_error' 参数来做到这一点。

# evaluate models
results = evaluate_models(models, metric='neg_mean_squared_error')

请注意,默认情况下,scikit-learn 会反转错误分数,以便最大化而不是最小化。这就是为什么均方误差为负,并在汇总时会有负号。因为分数被反转,我们可以继续假设我们在summarize_results()函数中最大化分数,并且不需要像我们在使用时所预期的那样指定 maximize = False 。错误指标。

完整的代码示例如下所示。

# regression spot check script
import warnings
from numpy import mean
from numpy import std
from matplotlib import pyplot
from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Lasso
from sklearn.linear_model import Ridge
from sklearn.linear_model import ElasticNet
from sklearn.linear_model import HuberRegressor
from sklearn.linear_model import Lars
from sklearn.linear_model import LassoLars
from sklearn.linear_model import PassiveAggressiveRegressor
from sklearn.linear_model import RANSACRegressor
from sklearn.linear_model import SGDRegressor
from sklearn.linear_model import TheilSenRegressor
from sklearn.neighbors import KNeighborsRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.tree import ExtraTreeRegressor
from sklearn.svm import SVR
from sklearn.ensemble import AdaBoostRegressor
from sklearn.ensemble import BaggingRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import ExtraTreesRegressor
from sklearn.ensemble import GradientBoostingRegressor

# load the dataset, returns X and y elements
def load_dataset():
	return make_regression(n_samples=1000, n_features=50, noise=0.1, random_state=1)

# create a dict of standard models to evaluate {name:object}
def get_models(models=dict()):
	# linear models
	models['lr'] = LinearRegression()
	alpha = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for a in alpha:
		models['lasso-'+str(a)] = Lasso(alpha=a)
	for a in alpha:
		models['ridge-'+str(a)] = Ridge(alpha=a)
	for a1 in alpha:
		for a2 in alpha:
			name = 'en-' + str(a1) + '-' + str(a2)
			models[name] = ElasticNet(a1, a2)
	models['huber'] = HuberRegressor()
	models['lars'] = Lars()
	models['llars'] = LassoLars()
	models['pa'] = PassiveAggressiveRegressor(max_iter=1000, tol=1e-3)
	models['ranscac'] = RANSACRegressor()
	models['sgd'] = SGDRegressor(max_iter=1000, tol=1e-3)
	models['theil'] = TheilSenRegressor()
	# non-linear models
	n_neighbors = range(1, 21)
	for k in n_neighbors:
		models['knn-'+str(k)] = KNeighborsRegressor(n_neighbors=k)
	models['cart'] = DecisionTreeRegressor()
	models['extra'] = ExtraTreeRegressor()
	models['svml'] = SVR(kernel='linear')
	models['svmp'] = SVR(kernel='poly')
	c_values = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for c in c_values:
		models['svmr'+str(c)] = SVR(C=c)
	# ensemble models
	n_trees = 100
	models['ada'] = AdaBoostRegressor(n_estimators=n_trees)
	models['bag'] = BaggingRegressor(n_estimators=n_trees)
	models['rf'] = RandomForestRegressor(n_estimators=n_trees)
	models['et'] = ExtraTreesRegressor(n_estimators=n_trees)
	models['gbm'] = GradientBoostingRegressor(n_estimators=n_trees)
	print('Defined %d models' % len(models))
	return models

# create a feature preparation pipeline for a model
def make_pipeline(model):
	steps = list()
	# standardization
	steps.append(('standardize', StandardScaler()))
	# normalization
	steps.append(('normalize', MinMaxScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

# evaluate a single model
def evaluate_model(X, y, model, folds, metric):
	# create the pipeline
	pipeline = make_pipeline(model)
	# evaluate model
	scores = cross_val_score(pipeline, X, y, scoring=metric, cv=folds, n_jobs=-1)
	return scores

# evaluate a model and try to trap errors and and hide warnings
def robust_evaluate_model(X, y, model, folds, metric):
	scores = None
	try:
		with warnings.catch_warnings():
			warnings.filterwarnings("ignore")
			scores = evaluate_model(X, y, model, folds, metric)
	except:
		scores = None
	return scores

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(X, y, models, folds=10, metric='accuracy'):
	results = dict()
	for name, model in models.items():
		# evaluate the model
		scores = robust_evaluate_model(X, y, model, folds, metric)
		# show process
		if scores is not None:
			# store a result
			results[name] = scores
			mean_score, std_score = mean(scores), std(scores)
			print('>%s: %.3f (+/-%.3f)' % (name, mean_score, std_score))
		else:
			print('>%s: error' % name)
	return results

# print and plot the top n results
def summarize_results(results, maximize=True, top_n=10):
	# check for no results
	if len(results) == 0:
		print('no results')
		return
	# determine how many results to summarize
	n = min(top_n, len(results))
	# create a list of (name, mean(scores)) tuples
	mean_scores = [(k,mean(v)) for k,v in results.items()]
	# sort tuples by mean score
	mean_scores = sorted(mean_scores, key=lambda x: x[1])
	# reverse for descending order (e.g. for accuracy)
	if maximize:
		mean_scores = list(reversed(mean_scores))
	# retrieve the top n for summarization
	names = [x[0] for x in mean_scores[:n]]
	scores = [results[x[0]] for x in mean_scores[:n]]
	# print the top n
	print()
	for i in range(n):
		name = names[i]
		mean_score, std_score = mean(results[name]), std(results[name])
		print('Rank=%d, Name=%s, Score=%.3f (+/- %.3f)' % (i+1, name, mean_score, std_score))
	# boxplot for the top n
	pyplot.boxplot(scores, labels=names)
	_, labels = pyplot.xticks()
	pyplot.setp(labels, rotation=90)
	pyplot.savefig('spotcheck.png')

# load dataset
X, y = load_dataset()
# get model list
models = get_models()
# evaluate models
results = evaluate_models(X, y, models, metric='neg_mean_squared_error')
# summarize results
summarize_results(results)

运行该示例总结了所评估的每个模型的表现,然后打印出前 10 个表现良好的算法的表现。

我们可以看到许多线性算法可能在这个问题上找到了相同的最优解。值得注意的是,那些表现良好的方法使用正则化作为一种​​特征选择,允许他们放大最佳解决方案。

这将表明在对此问题进行建模时特征选择的重要性,并且线性方法将成为关注的领域,至少目前是这样。

查看评估模型的打印分数还显示了对此问题执行的非线性和集成算法的差异程度。

...
>bag: -6118.084 (+/-1558.433)
>rf: -6127.169 (+/-1594.392)
>et: -5017.062 (+/-1037.673)
>gbm: -2347.807 (+/-500.364)

Rank=1, Name=lars, Score=-0.011 (+/- 0.001)
Rank=2, Name=ranscac, Score=-0.011 (+/- 0.001)
Rank=3, Name=lr, Score=-0.011 (+/- 0.001)
Rank=4, Name=ridge-0.0, Score=-0.011 (+/- 0.001)
Rank=5, Name=en-0.0-0.1, Score=-0.011 (+/- 0.001)
Rank=6, Name=en-0.0-0.8, Score=-0.011 (+/- 0.001)
Rank=7, Name=en-0.0-0.2, Score=-0.011 (+/- 0.001)
Rank=8, Name=en-0.0-0.7, Score=-0.011 (+/- 0.001)
Rank=9, Name=en-0.0-0.0, Score=-0.011 (+/- 0.001)
Rank=10, Name=en-0.0-0.3, Score=-0.011 (+/- 0.001)

在这种情况下,会创建一个盒子和胡须图,而不是真正为结果分析增加价值。

Boxplot of top 10 Spot-Checking Algorithms on a Regression Problem

回归问题前 10 个点检算法的箱形图

5.框架扩展

在本节中,我们将探讨采样检查框架的一些方便扩展。

课程网格搜索梯度提升

我发现自己使用 XGBoost 和梯度提升很多直接分类和回归问题。

因此,我喜欢在采样检查时使用方法的标准配置参数的课程网格。

下面是一个可以直接在现场检查框架中使用的功能。

# define gradient boosting models
def define_gbm_models(models=dict(), use_xgb=True):
	# define config ranges
	rates = [0.001, 0.01, 0.1]
	trees = [50, 100]
	ss = [0.5, 0.7, 1.0]
	depth = [3, 7, 9]
	# add configurations
	for l in rates:
		for e in trees:
			for s in ss:
				for d in depth:
					cfg = [l, e, s, d]
					if use_xgb:
						name = 'xgb-' + str(cfg)
						models[name] = XGBClassifier(learning_rate=l, n_estimators=e, subsample=s, max_depth=d)
					else:
						name = 'gbm-' + str(cfg)
						models[name] = GradientBoostingClassifier(learning_rate=l, n_estimators=e, subsample=s, max_depth=d)
	print('Defined %d models' % len(models))
	return models

默认情况下,该函数将使用 XGBoost 模型,但如果函数的use_xgb参数设置为False,则可以使用 sklearn 梯度增强模型。

同样,我们并没有尝试在问题上优化调整 GBM,只是很快找到配置空间中可能值得进一步调查的区域。

此功能可以直接用于分类和回归问题,只需稍微改变“XGBClassifier”到“XGBRegressor”和“GradientBoostingClassifier”到“[HTG6” ] GradientBoostingRegressor “。例如:

# define gradient boosting models
def get_gbm_models(models=dict(), use_xgb=True):
	# define config ranges
	rates = [0.001, 0.01, 0.1]
	trees = [50, 100]
	ss = [0.5, 0.7, 1.0]
	depth = [3, 7, 9]
	# add configurations
	for l in rates:
		for e in trees:
			for s in ss:
				for d in depth:
					cfg = [l, e, s, d]
					if use_xgb:
						name = 'xgb-' + str(cfg)
						models[name] = XGBRegressor(learning_rate=l, n_estimators=e, subsample=s, max_depth=d)
					else:
						name = 'gbm-' + str(cfg)
						models[name] = GradientBoostingXGBRegressor(learning_rate=l, n_estimators=e, subsample=s, max_depth=d)
	print('Defined %d models' % len(models))
	return models

为了具体化,下面是更新的二分类示例,以定义 XGBoost 模型。

# binary classification spot check script
import warnings
from numpy import mean
from numpy import std
from matplotlib import pyplot
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import RidgeClassifier
from sklearn.linear_model import SGDClassifier
from sklearn.linear_model import PassiveAggressiveClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import ExtraTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier
from xgboost import XGBClassifier

# load the dataset, returns X and y elements
def load_dataset():
	return make_classification(n_samples=1000, n_classes=2, random_state=1)

# create a dict of standard models to evaluate {name:object}
def define_models(models=dict()):
	# linear models
	models['logistic'] = LogisticRegression()
	alpha = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for a in alpha:
		models['ridge-'+str(a)] = RidgeClassifier(alpha=a)
	models['sgd'] = SGDClassifier(max_iter=1000, tol=1e-3)
	models['pa'] = PassiveAggressiveClassifier(max_iter=1000, tol=1e-3)
	# non-linear models
	n_neighbors = range(1, 21)
	for k in n_neighbors:
		models['knn-'+str(k)] = KNeighborsClassifier(n_neighbors=k)
	models['cart'] = DecisionTreeClassifier()
	models['extra'] = ExtraTreeClassifier()
	models['svml'] = SVC(kernel='linear')
	models['svmp'] = SVC(kernel='poly')
	c_values = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for c in c_values:
		models['svmr'+str(c)] = SVC(C=c)
	models['bayes'] = GaussianNB()
	# ensemble models
	n_trees = 100
	models['ada'] = AdaBoostClassifier(n_estimators=n_trees)
	models['bag'] = BaggingClassifier(n_estimators=n_trees)
	models['rf'] = RandomForestClassifier(n_estimators=n_trees)
	models['et'] = ExtraTreesClassifier(n_estimators=n_trees)
	models['gbm'] = GradientBoostingClassifier(n_estimators=n_trees)
	print('Defined %d models' % len(models))
	return models

# define gradient boosting models
def define_gbm_models(models=dict(), use_xgb=True):
	# define config ranges
	rates = [0.001, 0.01, 0.1]
	trees = [50, 100]
	ss = [0.5, 0.7, 1.0]
	depth = [3, 7, 9]
	# add configurations
	for l in rates:
		for e in trees:
			for s in ss:
				for d in depth:
					cfg = [l, e, s, d]
					if use_xgb:
						name = 'xgb-' + str(cfg)
						models[name] = XGBClassifier(learning_rate=l, n_estimators=e, subsample=s, max_depth=d)
					else:
						name = 'gbm-' + str(cfg)
						models[name] = GradientBoostingClassifier(learning_rate=l, n_estimators=e, subsample=s, max_depth=d)
	print('Defined %d models' % len(models))
	return models

# create a feature preparation pipeline for a model
def make_pipeline(model):
	steps = list()
	# standardization
	steps.append(('standardize', StandardScaler()))
	# normalization
	steps.append(('normalize', MinMaxScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

# evaluate a single model
def evaluate_model(X, y, model, folds, metric):
	# create the pipeline
	pipeline = make_pipeline(model)
	# evaluate model
	scores = cross_val_score(pipeline, X, y, scoring=metric, cv=folds, n_jobs=-1)
	return scores

# evaluate a model and try to trap errors and and hide warnings
def robust_evaluate_model(X, y, model, folds, metric):
	scores = None
	try:
		with warnings.catch_warnings():
			warnings.filterwarnings("ignore")
			scores = evaluate_model(X, y, model, folds, metric)
	except:
		scores = None
	return scores

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(X, y, models, folds=10, metric='accuracy'):
	results = dict()
	for name, model in models.items():
		# evaluate the model
		scores = robust_evaluate_model(X, y, model, folds, metric)
		# show process
		if scores is not None:
			# store a result
			results[name] = scores
			mean_score, std_score = mean(scores), std(scores)
			print('>%s: %.3f (+/-%.3f)' % (name, mean_score, std_score))
		else:
			print('>%s: error' % name)
	return results

# print and plot the top n results
def summarize_results(results, maximize=True, top_n=10):
	# check for no results
	if len(results) == 0:
		print('no results')
		return
	# determine how many results to summarize
	n = min(top_n, len(results))
	# create a list of (name, mean(scores)) tuples
	mean_scores = [(k,mean(v)) for k,v in results.items()]
	# sort tuples by mean score
	mean_scores = sorted(mean_scores, key=lambda x: x[1])
	# reverse for descending order (e.g. for accuracy)
	if maximize:
		mean_scores = list(reversed(mean_scores))
	# retrieve the top n for summarization
	names = [x[0] for x in mean_scores[:n]]
	scores = [results[x[0]] for x in mean_scores[:n]]
	# print the top n
	print()
	for i in range(n):
		name = names[i]
		mean_score, std_score = mean(results[name]), std(results[name])
		print('Rank=%d, Name=%s, Score=%.3f (+/- %.3f)' % (i+1, name, mean_score, std_score))
	# boxplot for the top n
	pyplot.boxplot(scores, labels=names)
	_, labels = pyplot.xticks()
	pyplot.setp(labels, rotation=90)
	pyplot.savefig('spotcheck.png')

# load dataset
X, y = load_dataset()
# get model list
models = define_models()
# add gbm models
models = define_gbm_models(models)
# evaluate models
results = evaluate_models(X, y, models)
# summarize results
summarize_results(results)

运行该示例表明,确实有些 XGBoost 模型在问题上表现良好。

...
>xgb-[0.1, 100, 1.0, 3]: 0.864 (+/-0.044)
>xgb-[0.1, 100, 1.0, 7]: 0.865 (+/-0.036)
>xgb-[0.1, 100, 1.0, 9]: 0.867 (+/-0.039)

Rank=1, Name=xgb-[0.1, 50, 1.0, 3], Score=0.872 (+/- 0.039)
Rank=2, Name=et, Score=0.869 (+/- 0.033)
Rank=3, Name=xgb-[0.1, 50, 1.0, 9], Score=0.868 (+/- 0.038)
Rank=4, Name=xgb-[0.1, 100, 1.0, 9], Score=0.867 (+/- 0.039)
Rank=5, Name=xgb-[0.01, 50, 1.0, 3], Score=0.867 (+/- 0.035)
Rank=6, Name=xgb-[0.1, 50, 1.0, 7], Score=0.867 (+/- 0.037)
Rank=7, Name=xgb-[0.001, 100, 0.7, 9], Score=0.866 (+/- 0.040)
Rank=8, Name=xgb-[0.01, 100, 1.0, 3], Score=0.866 (+/- 0.037)
Rank=9, Name=xgb-[0.001, 100, 0.7, 3], Score=0.866 (+/- 0.034)
Rank=10, Name=xgb-[0.01, 50, 0.7, 3], Score=0.866 (+/- 0.034)

Boxplot of top 10 Spot-Checking Algorithms on a Classification Problem with XGBoost

XGBoost 分类问题前 10 个采样检验算法的箱线图

重复评估

上述结果也突出了评估的嘈杂性,例如:此次运行中额外树木的结果与上面的运行不同(0.858 对 0.869)。

我们使用 k 折交叉验证来产生一个分数,但人口很少,计算的平均值会很吵。

只要我们将采样检查结果作为起点而不是算法对问题的明确结果,这就没问题了。这很难做到;它需要从业者的纪律。

或者,您可能希望调整框架,使模型评估方案更好地匹配您打算用于特定问题的模型评估方案。

例如,在评估诸如袋装或增强决策树之类的随机算法时,最好在相同的训练/测试集(称为重复)上多次运行每个实验,以便考虑学习算法的随机性质。

我们可以更新evaluate_model()函数来重复给定模型的 n 次评估,每次都有不同的数据分割,然后返回所有分数。例如,10 次交叉验证的三次重复将导致每次 30 分,以计算模型的平均表现。

# evaluate a single model
def evaluate_model(X, y, model, folds, repeats, metric):
	# create the pipeline
	pipeline = make_pipeline(model)
	# evaluate model
	scores = list()
	# repeat model evaluation n times
	for _ in range(repeats):
		# perform run
		scores_r = cross_val_score(pipeline, X, y, scoring=metric, cv=folds, n_jobs=-1)
		# add scores to list
		scores += scores_r.tolist()
	return scores

或者,您可能更喜欢从每个 k 倍交叉验证运行计算平均分数,然后计算所有运行的平均值,如下所述:

然后我们可以更新robust_evaluate_model()函数来传递重复参数和evaluate_models()函数来定义默认值,例如 3。

下面列出了具有三次重复模型评估的二分类示例的完整示例。

# binary classification spot check script
import warnings
from numpy import mean
from numpy import std
from matplotlib import pyplot
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import RidgeClassifier
from sklearn.linear_model import SGDClassifier
from sklearn.linear_model import PassiveAggressiveClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import ExtraTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier

# load the dataset, returns X and y elements
def load_dataset():
	return make_classification(n_samples=1000, n_classes=2, random_state=1)

# create a dict of standard models to evaluate {name:object}
def define_models(models=dict()):
	# linear models
	models['logistic'] = LogisticRegression()
	alpha = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for a in alpha:
		models['ridge-'+str(a)] = RidgeClassifier(alpha=a)
	models['sgd'] = SGDClassifier(max_iter=1000, tol=1e-3)
	models['pa'] = PassiveAggressiveClassifier(max_iter=1000, tol=1e-3)
	# non-linear models
	n_neighbors = range(1, 21)
	for k in n_neighbors:
		models['knn-'+str(k)] = KNeighborsClassifier(n_neighbors=k)
	models['cart'] = DecisionTreeClassifier()
	models['extra'] = ExtraTreeClassifier()
	models['svml'] = SVC(kernel='linear')
	models['svmp'] = SVC(kernel='poly')
	c_values = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for c in c_values:
		models['svmr'+str(c)] = SVC(C=c)
	models['bayes'] = GaussianNB()
	# ensemble models
	n_trees = 100
	models['ada'] = AdaBoostClassifier(n_estimators=n_trees)
	models['bag'] = BaggingClassifier(n_estimators=n_trees)
	models['rf'] = RandomForestClassifier(n_estimators=n_trees)
	models['et'] = ExtraTreesClassifier(n_estimators=n_trees)
	models['gbm'] = GradientBoostingClassifier(n_estimators=n_trees)
	print('Defined %d models' % len(models))
	return models

# create a feature preparation pipeline for a model
def make_pipeline(model):
	steps = list()
	# standardization
	steps.append(('standardize', StandardScaler()))
	# normalization
	steps.append(('normalize', MinMaxScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

# evaluate a single model
def evaluate_model(X, y, model, folds, repeats, metric):
	# create the pipeline
	pipeline = make_pipeline(model)
	# evaluate model
	scores = list()
	# repeat model evaluation n times
	for _ in range(repeats):
		# perform run
		scores_r = cross_val_score(pipeline, X, y, scoring=metric, cv=folds, n_jobs=-1)
		# add scores to list
		scores += scores_r.tolist()
	return scores

# evaluate a model and try to trap errors and hide warnings
def robust_evaluate_model(X, y, model, folds, repeats, metric):
	scores = None
	try:
		with warnings.catch_warnings():
			warnings.filterwarnings("ignore")
			scores = evaluate_model(X, y, model, folds, repeats, metric)
	except:
		scores = None
	return scores

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(X, y, models, folds=10, repeats=3, metric='accuracy'):
	results = dict()
	for name, model in models.items():
		# evaluate the model
		scores = robust_evaluate_model(X, y, model, folds, repeats, metric)
		# show process
		if scores is not None:
			# store a result
			results[name] = scores
			mean_score, std_score = mean(scores), std(scores)
			print('>%s: %.3f (+/-%.3f)' % (name, mean_score, std_score))
		else:
			print('>%s: error' % name)
	return results

# print and plot the top n results
def summarize_results(results, maximize=True, top_n=10):
	# check for no results
	if len(results) == 0:
		print('no results')
		return
	# determine how many results to summarize
	n = min(top_n, len(results))
	# create a list of (name, mean(scores)) tuples
	mean_scores = [(k,mean(v)) for k,v in results.items()]
	# sort tuples by mean score
	mean_scores = sorted(mean_scores, key=lambda x: x[1])
	# reverse for descending order (e.g. for accuracy)
	if maximize:
		mean_scores = list(reversed(mean_scores))
	# retrieve the top n for summarization
	names = [x[0] for x in mean_scores[:n]]
	scores = [results[x[0]] for x in mean_scores[:n]]
	# print the top n
	print()
	for i in range(n):
		name = names[i]
		mean_score, std_score = mean(results[name]), std(results[name])
		print('Rank=%d, Name=%s, Score=%.3f (+/- %.3f)' % (i+1, name, mean_score, std_score))
	# boxplot for the top n
	pyplot.boxplot(scores, labels=names)
	_, labels = pyplot.xticks()
	pyplot.setp(labels, rotation=90)
	pyplot.savefig('spotcheck.png')

# load dataset
X, y = load_dataset()
# get model list
models = define_models()
# evaluate models
results = evaluate_models(X, y, models)
# summarize results
summarize_results(results)

运行该示例可以更准确地估计分数。

...
>bag: 0.861 (+/-0.037)
>rf: 0.859 (+/-0.036)
>et: 0.869 (+/-0.035)
>gbm: 0.867 (+/-0.044)

Rank=1, Name=et, Score=0.869 (+/- 0.035)
Rank=2, Name=gbm, Score=0.867 (+/- 0.044)
Rank=3, Name=bag, Score=0.861 (+/- 0.037)
Rank=4, Name=rf, Score=0.859 (+/- 0.036)
Rank=5, Name=ada, Score=0.850 (+/- 0.035)
Rank=6, Name=ridge-0.9, Score=0.848 (+/- 0.038)
Rank=7, Name=ridge-0.8, Score=0.848 (+/- 0.038)
Rank=8, Name=ridge-0.7, Score=0.848 (+/- 0.038)
Rank=9, Name=ridge-0.6, Score=0.848 (+/- 0.038)
Rank=10, Name=ridge-0.5, Score=0.848 (+/- 0.038)

报告的方法仍然存在一些差异,但不到一次 k-fold 交叉验证。

可以增加重复次数以进一步减少这种变化,代价是运行时间较长,并且可能违背采样检查的意图。

各种输入表示

在拟合模型之前,我非常喜欢避免对数据表示的假设和建议。

相反,我也想检查输入数据的多个表示和变换,我将其称为视图。我在帖子中解释了这个:

我们可以更新框架,以便对每个模型的多个不同表示进行抽查。

一种方法是更新evaluate_models()函数,以便我们可以提供可用于每个已定义模型的make_pipeline()函数列表。

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(X, y, models, pipe_funcs, folds=10, metric='accuracy'):
	results = dict()
	for name, model in models.items():
		# evaluate model under each preparation function
		for i in range(len(pipe_funcs)):
			# evaluate the model
			scores = robust_evaluate_model(X, y, model, folds, metric, pipe_funcs[i])
			# update name
			run_name = str(i) + name
			# show process
			if scores is not None:
				# store a result
				results[run_name] = scores
				mean_score, std_score = mean(scores), std(scores)
				print('>%s: %.3f (+/-%.3f)' % (run_name, mean_score, std_score))
			else:
				print('>%s: error' % run_name)
	return results

然后,可以将所选择的流水线函数向下传递给robust_evaluate_model()函数以及可以使用它的evaluate_model()函数。

然后我们可以定义一堆不同的管道函数;例如:

# no transforms pipeline
def pipeline_none(model):
	return model

# standardize transform pipeline
def pipeline_standardize(model):
	steps = list()
	# standardization
	steps.append(('standardize', StandardScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

# normalize transform pipeline
def pipeline_normalize(model):
	steps = list()
	# normalization
	steps.append(('normalize', MinMaxScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

# standardize and normalize pipeline
def pipeline_std_norm(model):
	steps = list()
	# standardization
	steps.append(('standardize', StandardScaler()))
	# normalization
	steps.append(('normalize', MinMaxScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

然后创建一个可以提供给evaluate_models()函数的函数名列表。

# define transform pipelines
pipelines = [pipeline_none, pipeline_standardize, pipeline_normalize, pipeline_std_norm]

下面列出了更新为检查管道变换的分类案例的完整示例。

# binary classification spot check script
import warnings
from numpy import mean
from numpy import std
from matplotlib import pyplot
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import RidgeClassifier
from sklearn.linear_model import SGDClassifier
from sklearn.linear_model import PassiveAggressiveClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import ExtraTreeClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier

# load the dataset, returns X and y elements
def load_dataset():
	return make_classification(n_samples=1000, n_classes=2, random_state=1)

# create a dict of standard models to evaluate {name:object}
def define_models(models=dict()):
	# linear models
	models['logistic'] = LogisticRegression()
	alpha = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for a in alpha:
		models['ridge-'+str(a)] = RidgeClassifier(alpha=a)
	models['sgd'] = SGDClassifier(max_iter=1000, tol=1e-3)
	models['pa'] = PassiveAggressiveClassifier(max_iter=1000, tol=1e-3)
	# non-linear models
	n_neighbors = range(1, 21)
	for k in n_neighbors:
		models['knn-'+str(k)] = KNeighborsClassifier(n_neighbors=k)
	models['cart'] = DecisionTreeClassifier()
	models['extra'] = ExtraTreeClassifier()
	models['svml'] = SVC(kernel='linear')
	models['svmp'] = SVC(kernel='poly')
	c_values = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
	for c in c_values:
		models['svmr'+str(c)] = SVC(C=c)
	models['bayes'] = GaussianNB()
	# ensemble models
	n_trees = 100
	models['ada'] = AdaBoostClassifier(n_estimators=n_trees)
	models['bag'] = BaggingClassifier(n_estimators=n_trees)
	models['rf'] = RandomForestClassifier(n_estimators=n_trees)
	models['et'] = ExtraTreesClassifier(n_estimators=n_trees)
	models['gbm'] = GradientBoostingClassifier(n_estimators=n_trees)
	print('Defined %d models' % len(models))
	return models

# no transforms pipeline
def pipeline_none(model):
	return model

# standardize transform pipeline
def pipeline_standardize(model):
	steps = list()
	# standardization
	steps.append(('standardize', StandardScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

# normalize transform pipeline
def pipeline_normalize(model):
	steps = list()
	# normalization
	steps.append(('normalize', MinMaxScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

# standardize and normalize pipeline
def pipeline_std_norm(model):
	steps = list()
	# standardization
	steps.append(('standardize', StandardScaler()))
	# normalization
	steps.append(('normalize', MinMaxScaler()))
	# the model
	steps.append(('model', model))
	# create pipeline
	pipeline = Pipeline(steps=steps)
	return pipeline

# evaluate a single model
def evaluate_model(X, y, model, folds, metric, pipe_func):
	# create the pipeline
	pipeline = pipe_func(model)
	# evaluate model
	scores = cross_val_score(pipeline, X, y, scoring=metric, cv=folds, n_jobs=-1)
	return scores

# evaluate a model and try to trap errors and and hide warnings
def robust_evaluate_model(X, y, model, folds, metric, pipe_func):
	scores = None
	try:
		with warnings.catch_warnings():
			warnings.filterwarnings("ignore")
			scores = evaluate_model(X, y, model, folds, metric, pipe_func)
	except:
		scores = None
	return scores

# evaluate a dict of models {name:object}, returns {name:score}
def evaluate_models(X, y, models, pipe_funcs, folds=10, metric='accuracy'):
	results = dict()
	for name, model in models.items():
		# evaluate model under each preparation function
		for i in range(len(pipe_funcs)):
			# evaluate the model
			scores = robust_evaluate_model(X, y, model, folds, metric, pipe_funcs[i])
			# update name
			run_name = str(i) + name
			# show process
			if scores is not None:
				# store a result
				results[run_name] = scores
				mean_score, std_score = mean(scores), std(scores)
				print('>%s: %.3f (+/-%.3f)' % (run_name, mean_score, std_score))
			else:
				print('>%s: error' % run_name)
	return results

# print and plot the top n results
def summarize_results(results, maximize=True, top_n=10):
	# check for no results
	if len(results) == 0:
		print('no results')
		return
	# determine how many results to summarize
	n = min(top_n, len(results))
	# create a list of (name, mean(scores)) tuples
	mean_scores = [(k,mean(v)) for k,v in results.items()]
	# sort tuples by mean score
	mean_scores = sorted(mean_scores, key=lambda x: x[1])
	# reverse for descending order (e.g. for accuracy)
	if maximize:
		mean_scores = list(reversed(mean_scores))
	# retrieve the top n for summarization
	names = [x[0] for x in mean_scores[:n]]
	scores = [results[x[0]] for x in mean_scores[:n]]
	# print the top n
	print()
	for i in range(n):
		name = names[i]
		mean_score, std_score = mean(results[name]), std(results[name])
		print('Rank=%d, Name=%s, Score=%.3f (+/- %.3f)' % (i+1, name, mean_score, std_score))
	# boxplot for the top n
	pyplot.boxplot(scores, labels=names)
	_, labels = pyplot.xticks()
	pyplot.setp(labels, rotation=90)
	pyplot.savefig('spotcheck.png')

# load dataset
X, y = load_dataset()
# get model list
models = define_models()
# define transform pipelines
pipelines = [pipeline_none, pipeline_standardize, pipeline_normalize, pipeline_std_norm]
# evaluate models
results = evaluate_models(X, y, models, pipelines)
# summarize results
summarize_results(results)

运行该示例表明,我们通过将管道号添加到算法描述名称的开头来区分每个管道的结果,例如, '0rf'表示第一个管道的 RF,没有变换。

树算法的集合在这个问题上表现良好,并且这些算法对于数据缩放是不变的。这意味着它们在每个管道上的结果将是相似的(或相同的),反过来它们将挤出前 10 个列表中的其他算法。

...
>0gbm: 0.865 (+/-0.044)
>1gbm: 0.865 (+/-0.044)
>2gbm: 0.865 (+/-0.044)
>3gbm: 0.865 (+/-0.044)

Rank=1, Name=3rf, Score=0.870 (+/- 0.034)
Rank=2, Name=2rf, Score=0.870 (+/- 0.034)
Rank=3, Name=1rf, Score=0.870 (+/- 0.034)
Rank=4, Name=0rf, Score=0.870 (+/- 0.034)
Rank=5, Name=3bag, Score=0.866 (+/- 0.039)
Rank=6, Name=2bag, Score=0.866 (+/- 0.039)
Rank=7, Name=1bag, Score=0.866 (+/- 0.039)
Rank=8, Name=0bag, Score=0.866 (+/- 0.039)
Rank=9, Name=3gbm, Score=0.865 (+/- 0.044)
Rank=10, Name=2gbm, Score=0.865 (+/- 0.044)

进一步阅读

如果您希望深入了解,本节将提供有关该主题的更多资源。

摘要

在本教程中,您发现了点检查算法对新预测性建模问题的有用性,以及如何为 python 中的点检查算法开发标准框架以用于分类和回归问题。

具体来说,你学到了:

  • 采样检查提供了一种快速发现在预测性建模问题上表现良好的算法类型的方法。
  • 如何开发用于加载数据,定义模型,评估模型和总结结果的通用框架。
  • 如何应用框架进行分类和回归问题。

您是否使用过这个框架,或者您是否有进一步的建议来改进它? 请在评论中告诉我。

你有任何问题吗? 在下面的评论中提出您的问题,我会尽力回答。