
# 交叉验证

> 译者：[flink.sojb.cn](https://flink.sojb.cn/)


## 描述

当使用机器学习算法时，一个普遍存在的问题是_过度拟合_，或者当算法“内存”训练数据但是在外推到样本案例之外做得很差。处理过度拟合问题的常用方法是阻止原始训练算法中的某些数据子集，然后测量拟合算法在该保持集上的性能。这通常称为_交叉验证_。在一个数据子集上训练模型，然后在另一组数据上进行_验证_。

## 交叉验证策略

有几种保存数据的策略。FlinkML有方便的方法

*   训练测试分裂
*   训练 - 测试 - 保持分裂
*   K-Fold Splits
*   多随机拆分

### 训练测试分裂

最简单的分裂方法是`trainTestSplit`。此拆分采用DataSet和参数_分数_。该_分数_表示应分配给所述训练集合中的数据集的部分。这种拆分还需要两个额外的可选参数，_精确_和_种子_。

默认情况下，通过随机决定是否使用probability = _fraction_为训练DataSet分配观察来完成拆分。当_精确_是`true`然而，采取额外的步骤，以保证训练集是尽可能接近到DataSet的长度  ![](http://latex.codecogs.com/gif.latex?%E2%8B%85)  ![](http://latex.codecogs.com/gif.latex?) &lt;math xmlns="http://www.w3.org/1998/Math/MathML"&gt;&lt;mo&gt;⋅&lt;/mo&gt;&lt;/math&gt; _分数_。

该方法返回一个新`TrainTestDataSet`对象，该对象具有`.training`包含训练DataSet的`.testing`属性和包含测试DataSet 的属性。

### 训练 - 测试 - 保持分裂

在某些情况下，已知算法“学习”测试集。为了解决这个问题，列车测试持币观望策略，引入了二次抵抗组，形象地称为_抵抗_集。

传统上，将进行训练和测试以正常训练算法，然后将对保持集上的算法进行最终测试。理想情况下，保持集中的预测误差/模型分数与测试集中观察到的预测误差/模型分数没有显着差异。

在训练 - 测试 - 保持策略中，我们牺牲了初始拟合算法的样本大小，以增加我们的模型不过度拟合的置信度。

使用`trainTestHoldout`分离器时，_分数_ `Double`由长度为3 的_分数_数组代替。第一个数据元对应于用于训练的部分，第二个数据元用于测试，第三个数据元用于保持。该阵列的权重是_相对的_，例如，阵列`Array(3.0, 2.0, 1.0)`将导致大约50％的观测值在训练集中，33％的观测值在测试集中，17％的观测值在保持集中。

### K-Fold Splits

在_k折叠_策略中，DataSet被分成_k个_相等的子集。然后，对于_k_个子集中的每一个`TrainTestDataSet`，创建a，其中子集是`.training`DataSet，并且剩余的子集是该`.testing`集合。

对于每个训练集，训练算法，然后基于基于相关测试集的预测来评估算法。当在所保持的数据集上具有一致等级（例如预测误差）的算法时，我们可以确信我们的方法（例如，算法/算法参数的选择/迭代次数）对于过度拟合是鲁棒的。

[K-Cross交叉验证](https://en.wikipedia.org/wiki/Cross-validation_(statistics)#k-fold_cross-validation)

### 多随机拆分

在_多随机_策略可以看作是一个更一般的形式_列车测试抵抗_策略。实际上，它`.trainTestHoldoutSplit`是一个简单的打包器，`multiRandomSplit`它还将数据集打包到一个`trainTestHoldoutDataSet`对象中。

第一个主要区别是`multiRandomSplit`采用任意长度的分数数组。例如，可以创建多个保持集。或者，人们可以将其`kFoldSplit`视为`multiRandomSplit`（它是）的打包器，区别在于`kFoldSplit`创建大小相等的子集，其中`multiRandomSplit`将创建任何大小的子集。

第二个主要区别是`multiRandomSplit`返回一个DataSet _数组_，其大小和比例与它作为参数传递的_fraction数组_相等。

## 参数

各种`Splitter`方法共享许多参数。

| 参数 | 类型 | 描述 | 由Method使用 |
| --- | --- | --- | --- |
| `input` | `DataSet[Any]` | 要拆分的DataSet。 | `randomSplit`
`multiRandomSplit`
`kFoldSplit`
`trainTestSplit`
`trainTestHoldoutSplit` |
| `seed` | `Long` | 用于播种将DataSet分类到其他DataSet中的随机数生成器。 | `randomSplit`
`multiRandomSplit`
`kFoldSplit`
`trainTestSplit`
`trainTestHoldoutSplit` |
| `precise` | `Boolean` | 如果为true，请进一步努力使DataSet尽可能接近规定的比例。 | `randomSplit`
`trainTestSplit` |
| `fraction` | `Double` | `input`的一部分分配给第一个或`.training`DataSet。必须在范围（0,1） | `randomSplit`
`trainTestSplit` |
| `fracArray` | `Array[Double]` | 一个数组，规定了输出数据集的比例（比例不需要总和为1或者在范围（0,1）内） | `multiRandomSplit`
`trainTestHoldoutSplit` |
| `kFolds` | `Int` | 要将`input`DataSet 分解为的子集数。 | `kFoldSplit` |

## 例子



```
// An input dataset- does not have to be of type LabeledVector val data: DataSet[LabeledVector] = ...

// A Simple Train-Test-Split val dataTrainTest: TrainTestDataSet = Splitter.trainTestSplit(data, 0.6, true)

// Create a train test holdout DataSet val dataTrainTestHO: trainTestHoldoutDataSet = Splitter.trainTestHoldoutSplit(data, Array(6.0, 3.0, 1.0))

// Create an Array of K TrainTestDataSets val dataKFolded: Array[TrainTestDataSet] =  Splitter.kFoldSplit(data, 10)

// create an array of 5 datasets val dataMultiRandom: Array[DataSet[T]] = Splitter.multiRandomSplit(data, Array(0.5, 0.1, 0.1, 0.1, 0.1))
```



