一般来说,验证集越大,我们对模型质量的度量中的随机性(也称为“噪声”)就越小,它就越可靠。但是,通常我们只能通过划分出更多训练数据来获得一个大的验证集,而较小的训练数据集意味着更糟糕的模型!而交叉验证可是用来解决这个问题。
什么是交叉验证?
在交叉验证中,我们将数据集(一般为训练集,不包括验证集)等量划分成几个小的子集,然后对不同的子集运行建模过程,以获得每个子集模型的拟合效果的指标(可用MAE 平均绝对误差表示)。
- 我们将所有的数据集分为五部分(5 folds),每部分有20%的数据。
- 在实验1中,我们使用第一个折叠(1st-fold)作为一个验证集,其他所有数据作为训练数据。之后获得第一个训练的模型拟合效果的指标 ( M A E 1 ) (MAE_1) (MAE1?)
- 在实验2中,我们使用第二个折叠(2nd-fold)作为一个验证集(并使用除第二个折叠之外的所有内容来训练模型)。之后得到第二个训练的模型拟合效果的指标 ( M A E 2 ) (MAE_2) (MAE2?)
- 我们重复这个过程,每次用一个折叠作为验证集。知道所有的折叠都被用作过验证集。
- 比较五个MAE的值,MAE的值最小所对应的实验,获得的模型和参数即为最优模型和最优参数。
什么时候用交叉验证?
- 当数据较少时,用交叉验证cross-validation
- 当数据较大时,用简单验证法,将样本数据随机分为两部分(如80%训练集和20%训练集)。如果用交叉验证,那么耗时会过长。
- 没有简单的阈值来划分大数据集和小数据集。但是,如果模型需要几分钟或更少的时间运行,则可能值得切换到交叉验证。
- 或者,可以运行交叉验证,看看每个实验的分数是否接近。如果每个实验都得到差不多相同的结果,那么一个验证集(简单验证法)可能就足够了。
Example
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_scoredata = pd.read_csv('filename.csv')
X = data[['column_1','column_2']]
Y = data['column_3']model = RandomForestRegressor(m_estimators=100, random_state=0)# 将得分*(-1),因为scikit learn计算的是负的MAE
# cv是代表折叠的次数
scores = -1 * cross_val_score(model, X, y, cv=5, scoring='neg_mean_absolute_error')
print("MAE scores:\n", scores)
MAE scores:[301628.7893587 303164.4782723 287298.331666 236061.84754543 260383.45111427]
从MAE得分可以看出,实验四的MAE值最小,即该子集模型的拟合效果最好。
Scikit learn有一个约定,其中定义了所有度量,因此较高的数字更好。在这里使用否定词可以使它们与该惯例保持一致,尽管负的MAE在其他地方几乎闻所未闻。本质就是Scikit-Learn 交叉验证功能期望的是效用函数(越大越好)而不是损失函数(越低 越好),因此得分函数实际上与 MSE 相反(即负值)
print("Average MAE score (across experiments):")
print(scores.mean())
print("Standard deviation:")
print(np.sqrt(scores))
Average MAE score (across experiments):
277707.3795913405
Standard deviation:
23415.3123
此外,我们可以取所有实验(实验1~5)的平均值标准差,来获得该算法的精度。然后可以尝试着用不同算法进行实验,比教它们的精度,看哪个算法更适用于这个数据集。
以分层采样为基础的交叉验证
相较于函数cross_val_score()
或者其他相似函数所提供的功能。这种情况下,你可以实现你自己版本的交叉验证。事实上它相当直接。以下代码粗略地做了和 cross_val_score()
相同的事情,并且输出相同的结果。
from sklearn.model_selection import StratifiedKFold
from sklearn.linear_model import SGDClassifier
from sklearn.base import clonesgd_clf = SGDClassifier(max_iter=5, tol=-np.infty, random_state=42)# 对其中1折进行预测,对其他折进行训练
skfolds = StratifiedKFold(n_splits=3, random_state=42)for train_index, test_index in skfolds.split(X_train, y_train_5):clone_clf = clone(sgd_clf) X_train_folds = X_train[train_index]y_train_folds = (y_train_5[train_index])X_test_fold = X_train[test_index]y_test_fold = (y_train_5[test_index])clone_clf.fit(X_train_folds, y_train_folds)# 预测测试集中数据的分类类别y_pred = clone_clf.predict(X_test_fold)# 将预测得到的分类信息与测试集中原有的分类信息进行比较,求出相同的数量的和n_correct = sum(y_pred == y_test_fold) # 将该和除以总共预测的值的数量,计算准确率 print(n_correct / len(y_pred))
StratifiedKFold
类实现了分层采样(详见【纯随机采样(train_test_split)和分层采样(StratifiedShuffleSplit)| sklearn库实现】),生成的折(fold)包含了各 类相应比例。在每一次迭代,上述代码生成分类器的一个克隆版本,在训练折 (training folds)的克隆版本上进行训练,在测试折(test folds)上进行预测。然后它计算出正确预测的数目和预测的值的数量的比例,获得准确率。