4

我正在阅读 Hands on Machine Learning 这本书,作者谈到了训练和测试拆分期间的随机种子,在某个时间点,作者说在此期间机器会看到你的整个数据集。

作者正在使用以下函数来划分 Tran 和 Test 拆分,

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]

Usage of the function like this:
>>>train_set, test_set = split_train_test(housing, 0.2)
>>> len(train_set)
16512
>>> len(test_set)
4128

好吧,这可行,但并不完美:如果再次运行该程序,它将生成不同的测试集!随着时间的推移,您(或您的机器学习算法)将看到整个数据集,这是您想要避免的。

Sachin Rastogi:为什么以及如何影响我的模型性能?我知道每次运行时我的模型精度都会有所不同,因为训练集总是不同的。我的模型如何在一段时间内看到整个数据集?

作者还提供了一些解决方案,

一种解决方案是在第一次运行时保存测试集,然后在后续运行中加载它。另一种选择是在调用 np.random.permutation() 之前设置随机数生成器的种子(例如,np.random.seed(42)),以便它始终生成相同的随机索引。

但是,当您下次获取更新的数据集时,这两种解决方案都会中断。一个常见的解决方案是使用每个实例的标识符来决定它是否应该进入测试集(假设实例具有唯一且不可变的标识符)。

Sachin Rastogi:这会是一个很好的训练/测试部门吗?我认为不,训练和测试应该包含来自整个数据集的元素,以避免训练集中的任何偏差。

作者举个例子,

您可以计算每个实例标识符的哈希值,如果哈希值低于或等于最大哈希值的 20%,则将该实例放入测试集中。这可确保测试集在多次运行中保持一致,即使您刷新数据集也是如此。

新的测试集将包含 20% 的新实例,但不会包含之前在训练集中的任何实例。

Sachin Rastogi:我无法理解这个解决方案。能否请你帮忙?

4

1 回答 1

0

对我来说,这些是答案:

  1. 这里的要点是,在训练模型之前,您最好将部分数据(将构成您的测试集)放在一边。实际上,您想要实现的是能够很好地概括未见过的示例。通过运行您展示的代码,您将随着时间的推移获得不同的测试集;换句话说,您将始终在数据的不同子集上训练您的模型(并且可能在您之前标记为测试数据的数据上)。这反过来会影响训练,并且——达到极限——没有什么可以概括的。

  2. 如果不添加新数据,这确实是满足先前要求(具有稳定的测试集)的解决方案。

  3. 正如对您问题的评论中所说,通过散列每个实例的标识符,您可以确保旧实例总是被分配给相同的子集。

    • 在数据集更新之前放入训练集中的实例将保留在那里(因为它们的哈希值不会改变 - 因此它们的最左边的位 - 它将保持高于 0.2*max_hash_value);
    • 在更新数据集之前放入测试集中的实例将保留在那里(因为它们的哈希值不会改变,它将保持低于 0.2*max_hash_value)。

    更新后的测试集将包含 20% 的新实例以及与旧测试集关联的所有实例,使其保持稳定。

我还建议在这里查看作者的解释:https ://github.com/ageron/handson-ml/issues/71 。

于 2020-10-20T22:24:13.297 回答