# Kaggle 官方教程：机器学习中级5 交叉验证
> 原文：[Intermediate Machine Learning](https://www.kaggle.com/learn/intermediate-machine-learning) > [Cross-Validation](https://www.kaggle.com/alexisbcook/cross-validation)
> 
> 译者：[Leytton](https://github.com/Leytton)
> 
> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)

PS：水平有限，欢迎交流指正（Leytton@126.com）

在本节课程中，你将会学习如何使用交叉验证来评估模型性能。

## 1、介绍
机器学习是一个迭代的过程。

您将面临以下选择：使用什么预测变量、使用什么类型的模型、向这些模型提供什么参数等等。目前为止，你使用验证数据（或保留数据）评估模型质量来做出这些选择。

但这种方法也有一些缺点。假设你有一个5000行的数据集，通常你会保留大约20%（1000行）的数据作为验证数据。但这再模型评分中会带来随机变化，有时在一组1000行校验数据中表现良好，但在另一个1000行数据集中却不准确。

在极端情况下，你可以想象在验证数据集中只有一行数据。如果你比较不同的模型，那么哪一个模型预测效果最好主要取决于运气！

一般来说，验证数据集越大，评估模型质量中带来的随机性（即“噪音”）越小，越可靠。不幸的是，我们只能从训练数据中取出部分来获取更大的验证数据集，更小的训练数据集意味着更糟糕的模型！

## 2、什么是交叉验证？
在`交叉验证中`，我们使用不同的数据子集来执行建模过程，以获得模型质量的多个度量。

例如，我们可以将数据分成5个部分，每个部分占整个数据集的20%。.在这种情况下，我们将数据分成5个“**folds**”。

![tut5_crossval](/img/learn/intermediate-machine-learning/5.1.png)

然后，我们对每个fold进行一次实验：

 - 在**实验1**中，我们使用第一个fold作为验证（保留）数据集，其他fold为训练数据。这给我们一个基于20%保留数据集的模型质量度量。
 - 在**实验2**中，我们保留第二个fold的数据（其他fold为训练数据）。这将得到第二个模型质量评估结果。
 - 以此类推，使用每个fold作为验证数据集，我们最终得到的模型质量，是基于所有的行数据集(即使我们不同时使用所有行)。

## 3、什么时候使用交叉验证？
交叉验证为模型质量提供了更精确的度量，这在您进行大量建模决策时尤为重要。然而，它可能需要更长的时间来运行，因为它评估了多个模型（每个fold一个）。

所以，在此权衡之下，什么时候使用每种方法呢？

 - 对于小数据集，额外的计算并不是什么大事，你应该进行交叉验证。
 - 对于较大的数据集，一个验证数据集就够了。你的代码将会执行得更快，有足够的数据就没必要复用数据。

并没有一个明确的界限来区数据集是大还是小，但如果你的模型几分钟或更短时间就能跑完，那么久值得使用交叉验证。

或者，你可以运行交叉验证，看看每个实验的分数是否接近。如果每个实验都产生相同的结果，一个验证集可能就足够了。

## 4、案例

我们将会使用前面课程中相同的数据，加载输入数据`X`并输出数据到`y`。

然后我们定义一个`pipeline`，使用`填充器`来填充缺失数据，以及`随机森林模型`来做预测。

如果不使用	`pipeline`，来交叉验证是非常困难的！使用`pipeline`将会使代码非常简单。
```python
from sklearn.ensemble import RandomForestRegressor
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer

my_pipeline = Pipeline(steps=[('preprocessor', SimpleImputer()),
                              ('model', RandomForestRegressor(n_estimators=50,
                                                              random_state=0))
                             ])
```
我们使用`cross_val_score() `函数来获取交叉验证评分，通过`cv`参数来设置fold数量。
```python
from sklearn.model_selection import cross_val_score

# 乘以-1，因为sklearn计算得到的是负MAE值（neg_mean_absolute_error）
scores = -1 * cross_val_score(my_pipeline, 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]
```
`scoring`参数指定了模型质量的度量方法，我们选择`负的平均绝对误差值`，`scikit-learn`文档列出了[可选值](http://scikit-learn.org/stable/modules/model_evaluation.html)。

指定负MAE有点奇怪。Scikit-learn有一个约定，大的数字意味着更好的效果。在这里使用负号可以使它们与约定保持一致，尽管在其他地方几乎没有听说过。

我们通常需要模型质量的单一度量来比较不同的模型，所以取全部实验的平均值。
```python
print("Average MAE score (across experiments):")
print(scores.mean())
```
输出结果：
```
Average MAE score (across experiments):
277707.3795913405
```
## 5、结论
使用交叉验证能使模型质量更好，同时代码也更加简洁：注意我们不再需要跟踪每个的训练和验证集。尤其是对于小数据集，这是个很大的提升！

## 6、去吧，皮卡丘

把你的新技能运用到[下一个练习](https://www.kaggle.com/kernels/fork/3370281)中~
