乐趣区

关于深度学习:使用折外预测oof评估模型的泛化性能和构建集成模型

机器学习算法通常应用例如 kFold 等的穿插验证技术来进步模型的准确度。在穿插验证过程中,预测是通过拆分进去的不用于模型训练的测试集进行的。这些预测被称为折外预测(out-of-fold predictions)。折外预测在机器学习中施展着重要作用,能够进步模型的泛化性能。

在本文中,将介绍机器学习中的折外预测,次要包含以下几个方面:

  • 折外预测是对不用于训练模型的数据进行的一种样本外预测。
  • 在对看不见的数据进行预测时,折外预测最罕用于预计模型的性能。
  • 折外预测可用于构建集成模型,称为重叠泛化或重叠集成。

什么是折外预测?

应用重采样技术例如 k-fold 来评估机器学习算法在数据集上的性能是一种很常见的办法。k-fold 过程包含将训练数据集分成 k 组,而后在应用 k 组样本中的每一个作为测试集,而其余样本用作训练集。

这意味着训练和评估了 k 个不同的模型。这个过程能够总结如下:

1、随机打乱数据集。

2、将数据集分成 k 组。

3、对于每个独特的组:将该组作为一个保留数据用做测试,将残余的组作为训练数据集,在训练集上拟合模型并在测试集上进行评估,反复 k 次使得每一组保留数据都进行了测试。

4、最初预测时应用训练出的 K 个模型进行整合预测。

数据样本中的每个数据都被调配到一个独自的组中,并在整个过程中放弃在该组中。这意味着每个样本都有机会在 作为测试集保留至多 1 次,并作为训练集最多 k-1 次。折外预测是在重采样过程中对每组得保留数据(测试集)所做的那些预测。如果正确执行,训练数据集中的每个数据都会有一个预测。

折外预测的概念与样本外预测(Out-of-Sample)的概念间接相干,因为这两种状况下的预测都是在模型训练期间未应用的样本上进行的,并且都能够预计模型在对新数据进行预测时的性能。折外预测也是一种样本外预测,只管它应用了 k -fold 穿插验证来评估模型。

上面咱们看看折外预测的两个次要性能

应用折外预测进行模型的评估

折外预测最常见的用处是评估模型的性能。应用诸如谬误或准确率之类的评分指标对未用于模型训练的数据进行预测和评估。相当用于应用了新数据(训练时不可见的数据)进行预测和对模型性能的预计,应用不可见的数据能够评估模型的泛化性能,也就是模型是否过拟合了。

对模型在每次训练期间所做的预测进行评分,而后计算这些分数的平均值是最罕用的模型评估办法。例如,如果一个分类模型,能够在每组预测上计算分类准确度,而后将性能预计为对每组折外预测预计的均匀分数。

上面能够通过一个小的示例展现应用折外预测的模型评估。首先,应用 scikit-learn 的 make_blobs() 函数创立一个蕴含 1,000 个样本、两个类和 100 个输出特色的二元分类问题。

上面的代码筹备了一个数据样本并打印了数据集的输出和输入元素的形态。

from sklearn.datasets import make_blobs
# create the inputs and outputs
X, y = make_blobs(n_samples=1000, centers=2, n_features=100, cluster_std=20)
# summarize the shape of the arrays
print(X.shape, y.shape)

运行该示例会打印输出数据的形态,显示 1,000 行数据和 100 列或输出特色以及相应的分类标签。

下一步应用 KFold 来对数据进行分组训练 KNeighborsClassifier 模型。

咱们将对 KFold 应用 k=10 参数,这是正当的默认值,在每组数据上拟合一个模型,并在每组的保留数据上进行测试评估。

评分保留在每个模型评估的列表中,并打印这些分数的平均值和标准差。

# evaluate model by averaging performance across each fold
from numpy import mean
from numpy import std
from sklearn.datasets import make_blobs
from sklearn.model_selection import KFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# create the inputs and outputs
X, y = make_blobs(n_samples=1000, centers=2, n_features=100, cluster_std=20)
# k-fold cross validation
scores = list()
kfold = KFold(n_splits=10, shuffle=True)
# enumerate splits
for train_ix, test_ix in kfold.split(X):
# get data
train_X, test_X = X[train_ix], X[test_ix]
train_y, test_y = y[train_ix], y[test_ix]
# fit model
model = KNeighborsClassifier()
model.fit(train_X, train_y)
# evaluate model
yhat = model.predict(test_X)
acc = accuracy_score(test_y, yhat)
# store score
scores.append(acc)
print('>', acc)
# summarize model performance
mean_s, std_s = mean(scores), std(scores)
print('Mean: %.3f, Standard Deviation: %.3f' % (mean_s, std_s))

留神:后果可能会因算法或评估过程的随机性或数值精度的差别而有所不同。在运行完结时,打印的分数的平均值和标准差如下:

>  0.95
>  0.92
>  0.95
>  0.95
>  0.91
>  0.97
>  0.96
>  0.96
>  0.98
>  0.91
Mean: 0.946, Standard Deviation: 0.023

除对每个模型的预测评估进行均匀以外,还能够将每个模型的预测聚合成一个列表,这个列表中蕴含了每组训练时作为测试集的保留数据的汇总。在所有的模型训练实现后将该列表作为一个整体以取得单个的准确率分数。

应用这种办法是思考到每个数据在每个测试集中只呈现一次。也就是说,训练数据集中的每个样本在穿插验证过程中都有一个预测。所以能够收集所有预测并将它们与指标后果进行比拟,并在整个训练完结后计算分数。这样的益处是更能突出模型的泛化性能。

残缺的代码如下

# evaluate model by calculating the score across all predictions
from sklearn.datasets import make_blobs
from sklearn.model_selection import KFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# create the inputs and outputs
X, y = make_blobs(n_samples=1000, centers=2, n_features=100, cluster_std=20)
# k-fold cross validation
data_y, data_yhat = list(), list()
kfold = KFold(n_splits=10, shuffle=True)
# enumerate splits
for train_ix, test_ix in kfold.split(X):
# get data
train_X, test_X = X[train_ix], X[test_ix]
train_y, test_y = y[train_ix], y[test_ix]
# fit model
model = KNeighborsClassifier()
model.fit(train_X, train_y)
# make predictions
yhat = model.predict(test_X)
# store
data_y.extend(test_y)
data_yhat.extend(yhat)
# evaluate the model
acc = accuracy_score(data_y, data_yhat)
print('Accuracy: %.3f' % (acc))

每个保留数据集的所有预期值和预测值在运行完结时打印出单个准确度得分。

Accuracy: 0.930

除了对模型评估以外,折外预测的最大作用就是能够进行模型的集成,进步泛化能力。

折外预测进行模型集成

集成学习是一种机器学习的办法,它在同一训练数据上训练多个模型,并将多个模型的预测进行集成以进步整体的性能。这也是在进行机器学习比赛时最常见办法。

首先,对每个模型都进行进行穿插验证并收集所有的折外预测。须要留神的是每个模型执行数据拆分必须是雷同的。这样就能够取得所有的折外预测。这样就取得了 Base-Model:在训练数据集上应用 k 折穿插验证评估的模型,并保留所有非折叠预测。

下一步依据其余模型的预测训练一个高阶模型(也被称为 Meta-Model)。这个模型的工作是学习如何最好地联合和纠正其余模型使得这些(其余)模型的折外预测可能取得更好的性能。

听起来很绕口,上面还是应用一个简略的二分类问题进行解释,首先训练一个决策树和一个 k 最近邻模型作为 Base-Model。每个 Base-Model 通过 折外预测为训练数据集中的每个样本预测 0 或 1。这些预测与输出数据一起输出到高阶模型(Meta-Model)中。

  • Meta-Model 输出:Base-Model 的输出特色 +Base-Model 的预测。
  • Meta-Model 输入:样本的指标(与 Base-Models 雷同)。

为什么要应用折外预测来训练 Meta-Model?

在整个训练数据集上训练 Base-Model,而后对训练数据集中的每个样本进行预测,并将预测用作 Meta-Model 的输出,这样其实所有的样本都用 Meta-Model 训练,预测必定比失常状况更好(非常容易产生过拟合),并且 Meta-Model 可能不会对纠正 Base-Model 预测产生任何的帮忙,甚至会使后果变差。

然而应用 Base-Model 的折外预测来训练 Meta-Model,Meta-Model 能够是应用 Base-Model 看不见的数据进行操作,能够取得 Base-Model 对新数据预测行为的有余并通过训练来纠正 Base-Model 的问题,这就像应用集成学习时的状况一样:应用的都是训练时不可见的新数据。

通过穿插验证每个 Base-Model 也都是在整个数据集上进行训练,这些最终的 Base-Model 和 Meta-Model 可用于对新数据进行预测。这个过程能够总结如下:

  • 对于每个 Base-Model,应用穿插验证训练并保留折外预测。
  • 应用 Base-Model 中的折外预测进行 Meta-Model 的训练。

这一过程称为 Stacked Generalization(重叠泛化) 简称重叠。通常应用线性加权和作为 Meta-Model,这个过程有时✌被称为 blending。

代码实现

这里能够应用上一节中雷同数据具体介绍这个过程。首先将数据拆分为训练和验证数据集。训练数据集将用于拟合 Base-Model 和 Meta-Model,验证数据集将在训练完结时用于评估 Meta-Model 和 Base-Model。

X, X_val, y, y_val = train_test_split(X, y, test_size=0.33)

下一步应用 穿插验证来拟合每折的 DecisionTreeClassifier 和 KNeighborsClassifier 模型并保留折外预测。这些模型将输入概率而不是类别标签,因为须要为 Meta-Model 提供更有用的输出特色。。

# collect out of sample predictions
data_x, data_y, knn_yhat, cart_yhat = list(), list(), list(), list()
kfold = KFold(n_splits=10, shuffle=True)
for train_ix, test_ix in kfold.split(X):
# get data
train_X, test_X = X[train_ix], X[test_ix]
train_y, test_y = y[train_ix], y[test_ix]
data_x.extend(test_X)
data_y.extend(test_y)
# fit and make predictions with cart
model1 = DecisionTreeClassifier()
model1.fit(train_X, train_y)
yhat1 = model1.predict_proba(test_X)[:, 0]
cart_yhat.extend(yhat1)
# fit and make predictions with cart
model2 = KNeighborsClassifier()
model2.fit(train_X, train_y)
yhat2 = model2.predict_proba(test_X)[:, 0]
knn_yhat.extend(yhat2)

以上的代码为 Meta-Model 构建了数据集,该数据集由输出数据的 100 个输出特色和来自 kNN 和决策树模型的两个预测概率组成。

上面的 create_meta_dataset() 函数 将折外的数据和预测作为输出,并为 Meta-Model 构建输出数据集。

def create_meta_dataset(data_x, yhat1, yhat2):
# convert to columns
yhat1 = array(yhat1).reshape((len(yhat1), 1))
yhat2 = array(yhat2).reshape((len(yhat2), 1))
# stack as separate columns
meta_X = hstack((data_x, yhat1, yhat2))
return meta_X

而后调用这个函数来为 Meta-Model 筹备数据。

meta_X = create_meta_dataset(data_x, knn_yhat, cart_yhat)

将每个 Base-Model 拟合到整个训练数据集上,并应用验证集进行预测。

# fit final submodels
model1 = DecisionTreeClassifier()
model1.fit(X, y)
model2 = KNeighborsClassifier()
model2.fit(X, y)

而后在筹备好的数据集上 Meta-Model,这里咱们应用 LogisticRegression 模型。

# construct meta classifier
meta_model = LogisticRegression(solver='liblinear')
meta_model.fit(meta_X, data_y)

最初,应用 Meta-Model 对保留数据集进行预测。首先通过 Base-Model,输入用于构建 Meta-Model 的数据集,而后应用 Meta-Model 进行预测。把所有这些操作封装到 stack_prediction() 的函数中。

# make predictions with stacked model
def stack_prediction(model1, model2, meta_model, X):
# make predictions
yhat1 = model1.predict_proba(X)[:, 0]
yhat2 = model2.predict_proba(X)[:, 0]
# create input dataset
meta_X = create_meta_dataset(X, yhat1, yhat2)
# predict
return meta_model.predict(meta_X)

应用最后宰割的保留数据集进行 Base-Model 的验证

# evaluate sub models on hold out dataset
acc1 = accuracy_score(y_val, model1.predict(X_val))
acc2 = accuracy_score(y_val, model2.predict(X_val))
print('Model1 Accuracy: %.3f, Model2 Accuracy: %.3f' % (acc1, acc2))
# evaluate meta model on hold out dataset
yhat = stack_prediction(model1, model2, meta_model, X_val)
acc = accuracy_score(y_val, yhat)
print('Meta Model Accuracy: %.3f' % (acc))

将下面所有的代码合并,残缺的代码如下:

# example of a stacked model for binary classification
from numpy import hstack
from numpy import array
from sklearn.datasets import make_blobs
from sklearn.model_selection import KFold
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# create a meta dataset
def create_meta_dataset(data_x, yhat1, yhat2):
# convert to columns
yhat1 = array(yhat1).reshape((len(yhat1), 1))
yhat2 = array(yhat2).reshape((len(yhat2), 1))
# stack as separate columns
meta_X = hstack((data_x, yhat1, yhat2))
return meta_X

# make predictions with stacked model
def stack_prediction(model1, model2, meta_model, X):
# make predictions
yhat1 = model1.predict_proba(X)[:, 0]
yhat2 = model2.predict_proba(X)[:, 0]
# create input dataset
meta_X = create_meta_dataset(X, yhat1, yhat2)
# predict
return meta_model.predict(meta_X)

# create the inputs and outputs
X, y = make_blobs(n_samples=1000, centers=2, n_features=100, cluster_std=20)
# split
X, X_val, y, y_val = train_test_split(X, y, test_size=0.33)
# collect out of sample predictions
data_x, data_y, knn_yhat, cart_yhat = list(), list(), list(), list()
kfold = KFold(n_splits=10, shuffle=True)
for train_ix, test_ix in kfold.split(X):
# get data
train_X, test_X = X[train_ix], X[test_ix]
train_y, test_y = y[train_ix], y[test_ix]
data_x.extend(test_X)
data_y.extend(test_y)
# fit and make predictions with cart
model1 = DecisionTreeClassifier()
model1.fit(train_X, train_y)
yhat1 = model1.predict_proba(test_X)[:, 0]
cart_yhat.extend(yhat1)
# fit and make predictions with cart
model2 = KNeighborsClassifier()
model2.fit(train_X, train_y)
yhat2 = model2.predict_proba(test_X)[:, 0]
knn_yhat.extend(yhat2)
# construct meta dataset
meta_X = create_meta_dataset(data_x, knn_yhat, cart_yhat)
# fit final submodels
model1 = DecisionTreeClassifier()
model1.fit(X, y)
model2 = KNeighborsClassifier()
model2.fit(X, y)
# construct meta classifier
meta_model = LogisticRegression(solver='liblinear')
meta_model.fit(meta_X, data_y)
# evaluate sub models on hold out dataset
acc1 = accuracy_score(y_val, model1.predict(X_val))
acc2 = accuracy_score(y_val, model2.predict(X_val))
print('Model1 Accuracy: %.3f, Model2 Accuracy: %.3f' % (acc1, acc2))
# evaluate meta model on hold out dataset
yhat = stack_prediction(model1, model2, meta_model, X_val)
acc = accuracy_score(y_val, yhat)
print('Meta Model Accuracy: %.3f' % (acc))

下面的残缺代码首先打印了决策树和 kNN 模型的准确性,而后打印最终 Meta-Model 在保留数据集上的性能,能够看到元模型的体现优于两个 Base-Model。

Model1 Accuracy: 0.670, Model2 Accuracy: 0.930
Meta-Model Accuracy: 0.955

能够看到尽管模型 1 的准确率只有 67%,然而通过折外预测的集成办法也对最终的后果产生的良好的影响。

总结

  • 折外预测是对不用于训练模型的数据进行的一种样本外预测。
  • 在对看不见的数据进行预测时,折外预测最罕用于预计模型的性能。
  • 折外预测还可用于构建集成模型,称为重叠泛化或重叠集成。

https://www.overfit.cn/post/1ebf8320e9934d02ad74bafd198d67b5

作者:Jason Brownlee PhD

退出移动版