学习一个预测函数的参数并在相同的数据上进行测试是一个方法上的错误: 一个模型只是重复它刚刚看到的样本的标签就会得到一个完美的分数,但是不能预测任何有用的尚未看到的数据。这种情况叫做过拟合(overfitting)。为了避免这种情况,在进行(有监督的)机器学习实验时,通常的做法是将部分可用数据作为测试集 X _ test,y _ test。请注意,“实验”一词并不仅仅指学术用途,因为即使在商业环境中,机器学习通常也是从实验开始的。下面是模型训练中典型的交叉验证工作流程图。通过网格搜索技术可以确定最佳参数。
在 scikit-learn 中,可以使用train _ test _ split辅助函数快速计算随机分割为训练集和测试集的结果。让我们加载iris数据集,以拟合它的线性支持向量机:
train _ test _ split
iris
import numpy as np from sklearn.model_selection import train_test_split from sklearn import datasets from sklearn import svm X, y = datasets.load_iris(return_X_y=True) X.shape, y.shape
((150, 4), (150,))
我们现在可以快速抽样一个训练集,同时拿出40% 的数据来测试(评估)我们的分类器:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0)
X_train.shape, y_train.shape
((90, 4), (90,))
X_test.shape, y_test.shape
((60, 4), (60,))
clf = svm.SVC(kernel='linear', C=1).fit(X_train, y_train) clf.score(X_test, y_test)
0.9666666666666667
当评估估计器的不同设置(“超参数”)时,例如必须为支持向量机手动设置的 C 设置,仍然存在测试集过拟合的风险,因为参数可以被调整,直到估计器执行最佳。这样,关于测试集的知识就可以“泄漏”到模型中,评估指标就不再报告泛化性能。为了解决这个问题,数据集的另一部分可以作为所谓的“验证集”: 训练在训练集上进行,之后在验证集上进行评估,当实验似乎成功时,可以在测试集上进行最终评估。
然而,通过将可用数据划分为三个集合,我们大大减少了可用于学习模型的样本数量,并且结果可以依赖于一对(训练,验证)集合的特定随机选择。
解决这个问题的方法是一个叫做交叉验证的程序(简称 CV)。测试集仍然应该等待最终的评估,但是在进行 CV 时不再需要验证集。在称为 k 倍 CV 的基本方法中,训练集被划分为 k 个较小的集(下面描述其他方法,但通常遵循相同的原则)。对于每个 k“折叠”都遵循以下步骤:
然后,k 倍交叉验证报告的性能指标就是循环中计算的值的平均值。这种方法在计算上可能很昂贵,但是不会浪费太多的数据(在修复任意验证集时就是这种情况) ,这在诸如逆向推理等样本数量非常少的问题中是一个主要的优势。
使用交叉验证最简单的方法是对估计器和数据集调用cross _ val _ score函数。以下示例说明如何透过分割数据、拟合模型及连续5次计算得分(每次不同的分割) ,估计iris数据集的线性内核支持向量机的准确度:
cross _ val _ score
from sklearn.model_selection import cross_val_score clf = svm.SVC(kernel='linear', C=1, random_state=42) scores = cross_val_score(clf, X, y, cv=5) scores
array([0.96666667, 1. , 0.96666667, 0.96666667, 1. ])
因此,平均分及标准差由以下方法计算:
print("%0.2f accuracy with a standard deviation of %0.2f" % (scores.mean(), scores.std()))
0.98 accuracy with a standard deviation of 0.02
默认情况下,在每个 CV 迭代中计算的得分是估计器的得分方法。可以通过使用scoring参数来改变这一点:
scoring
from sklearn import metrics scores = cross_val_score(clf, X, y, cv=5, scoring='f1_macro') scores
array([0.96658312, 1. , 0.96658312, 0.96658312, 1. ])
在iris数据集的情况下,样本是平衡的目标类,因此accuracy和F1-score几乎相等。当 cv 参数是一个整数时,cross _ val _ score 默认使用 KFold 或 StratifiedKFold策略,如果估计器派生自 ClassfierMixin,则使用后者。
accuracy
F1-score
KFold
StratifiedKFold
还可以通过传递交叉验证迭代器来使用其他交叉验证策略,例如:
from sklearn.model_selection import ShuffleSplit n_samples = X.shape[0] cv = ShuffleSplit(n_splits=5, test_size=0.3, random_state=0) cross_val_score(clf, X, y, cv=cv)
array([0.97777778, 0.97777778, 1. , 0.95555556, 1. ])
另一种选择是使用可迭代的产生(train,test)拆分作为索引数组,例如:
def custom_cv_2folds(X): n = X.shape[0] i = 1 while i <= 2: idx = np.arange(n * (i - 1) / 2, n * i / 2, dtype=int) yield idx, idx i += 1 custom_cv = custom_cv_2folds(X) cross_val_score(clf, X, y, cv=custom_cv)
array([1. , 0.97333333])
保留数据的数据转换
正如测试一个预测器对于从训练、预处理(例如标准化、特征选择等)和类似的数据转换中提取出来的数据是重要的一样,类似地,应该从训练集中学习并应用于提取出来的数据进行预测:
from sklearn import preprocessing X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=0) scaler = preprocessing.StandardScaler().fit(X_train) X_train_transformed = scaler.transform(X_train) clf = svm.SVC(C=1).fit(X_train_transformed, y_train) X_test_transformed = scaler.transform(X_test) clf.score(X_test_transformed, y_test)
0.9333333333333333
管道使得构建估计器更加容易,在交叉验证下提供这种行为:
from sklearn.pipeline import make_pipeline clf = make_pipeline(preprocessing.StandardScaler(), svm.SVC(C=1)) cross_val_score(clf, X, y, cv=cv)
array([0.97777778, 0.93333333, 0.95555556, 0.93333333, 0.97777778])
Cross _ valid函数与 cross _ val _ score 有两个不同之处:
Cross _ valid
[‘ test _ score’、‘ fit _ time’、‘ score _ time’]
[‘ test _ < scoer1 _ name >’,‘ test _ < scoer2 _ name >’,‘ test _ < scoer... >’,‘ fit _ time’,‘ score _ time’]
Return _ train _ score
return _ Estiator = True
from sklearn.model_selection import cross_validate from sklearn.metrics import recall_score scoring = ['precision_macro', 'recall_macro'] clf = svm.SVC(kernel='linear', C=1, random_state=0) scores = cross_validate(clf, X, y, scoring=scoring) sorted(scores.keys())
['fit_time', 'score_time', 'test_precision_macro', 'test_recall_macro']