为什么作者在《动手机器学习》一书中建议不要使用random.seed



我一直在阅读scikit learn、keras。。。Aurélien Géron(第2版),在第54-55页上,他讨论了创建测试集的步骤。

他使用了numpy的random.permutation方法,但他说这有一个问题,即每次我们运行这个程序时,它都会创建一个不同的测试集,最终我们的算法会看到整个测试集,这并不好,所以他说要么生成一次数据集,然后每次加载它,要么每次都使用numpy的random.seed来获得相同的实例。

这是numpy方法的代码:

import numpy as np
def split_train_test(data, test_ratio):
shuffled_indices = np.random.permutation(len(data))
test_set_size = int(len(data) * test_ratio)
test_indices = shuffled_indices[:test_set_size]
train_indices = shuffled_indices[test_set_size:]
return data.iloc[train_indices], data.iloc[test_indices]

此外,他说";但这两种解决方案都将在下次获取更新的数据集时失效";,现在我明白了保存一次并加载方法的情况。但我不明白为什么numpy方法会出现这种情况,因为它是从输入数据集创建测试集的,所以如果我们每次都向它提供更新的数据集,那么原始数据集中的任何更改都应该持续存在,对吗?

我还读过一篇文章,解释了为什么使用numpy.random的全局种子不好,而我们应该使用生成器实例的方法,这是有意义的。

但我仍在努力理解作者的推理,即为什么这两种方法都会失败,以及为什么他使用哈希和来创建测试集

首先,算法不会看到所有的数据,否则测试拆分将过时,正如您所理解的那样。

因此,所有这些参数都解决了程序运行不止一次的情况。例如,如果用户将重新运行训练,或者进一步训练预先训练的网络,则可能发生这种情况。如果发生这种情况,我们需要确保测试拆分保持隐藏状态。测试数据用于比较不同的模型,因此,如果在不同的测试数据上评估两个模型,则无法以正确的方式进行比较。还请注意,人们通常会对训练、测试和验证数据进行区分。。。

因此,每次都随机拆分是个坏主意。

或者,他建议制作一个";确定性";使用种子随机分割。每次程序启动时,将种子设置为相同的值,它将创建相同的随机数序列,这很好。然而,如果数据的顺序发生变化,例如,文件名发生变化或首先是无序的;"随机";数字不再能解决这个问题。

然后,他建议可以将测试拆分单独保存到光盘中,以防止多次拆分数据。这是一个很好的解决随机数问题的方法。

然而,鸟类说,当有新的数据可供使用时,需要创建一个新的分裂,其中也包含新物种。如果预先训练的狗猫网络现在进行了微调,则不能保证新的天真分裂会将旧的训练数据泄露到新的测试数据集,从而使您相信您的模型比实际情况更好。

我认为作者想警告读者,这些事情发生得比你预期的要容易,并希望读者思考当网络对新数据进行微调或更新训练和测试数据时会发生什么或可能发生什么。当你意识到这一点时,你总是会找到一种方法来合并新数据,而不会造成麻烦。

"但这两种解决方案都将在下次获取更新的数据集";

突出显示引用文本的关键部分。更新后的数据集与原始数据集不同。

如果你设置了相同的随机种子,那么np.random.permutation()应该返回相同的数字排列,但是数据不相同,所以你不会得到相同的训练/测试分割。您可以使用不同的数据集,每个数据集具有相同的行数,并且它们将在相同的索引上拆分。

散列函数为给定的输入生成一个数字。该函数可以生成一个值,该值可以用作标识数据集中每一行的索引,而不是使用数据集中的行数。然后,您可以使用索引来执行训练/测试拆分。

您可以在索引中选择分割数据的点,只要保持不变,数据就会保持一致。

这让你确信,如果你更新数据集,那么使用哈希函数将确保原始数据仍然具有相同的哈希值,因此不会在训练集和测试集之间移动。任何新数据都将根据生成的哈希值添加到训练或测试集中。

如果数据集不包含用于哈希函数的唯一标识符,则可能需要执行额外的工作。