在机器学习中,一种常见的困境是过拟合(overfitting)——指一个在训练数据上表现良
好,但对任何新数据的泛化能力却很差的模型。 这可能牵扯到对数据中噪声的学习,也可
能涉及学习识别特别的输入,而不是对可以得到期望的输出进行准确预测的任何因素。
另一种有害的情况是欠拟合(underfitting),它产生的模型甚至在训练数据上都没有好的表
现,尽管通常这暗示你模型不够好而要继续寻找改进的模型。
水平线显示了最佳拟合阶数为 0(也就是常数)的多项式, 它对训练数据来说存在严重的
欠拟合。最佳拟合的阶数为 9(也就是有 10 个参数)的多项式精确地穿过训练数据的每个
点,但这是严重过拟合的。如果我们能取到更多的一些点, 这个多项式很有可能会偏离它
们很多。阶数为 1 的线把握了很好的平衡——它和每个点都很接近,并且(如果这些数据
是有代表性的)它也会和新的数据点很接近。
很明显,太复杂的模型会导致过拟合,并且在训练数据集之外不能很好地泛化。所以,我
们该如何确保我们的模型不会太复杂呢? 最基本的方法包括使用不同的数据来训练和测试
模型。
最简单的做法是划分数据集, 使得(比如说)三分之二的数据用来训练模型,之后用剩余
的三分之一来衡量模型的表现:
def split_data(data, prob):
"""split data into fractions [prob, 1 - prob]"""
results = [], []
for row in data:
results[0 if random.random() < prob else 1].append(row)
return results
通常我们会有一个作为输入变量的矩阵 x 和一个作为输出变量的向量 y。这种情况下,我
们要确保无论在训练数据还是测试数据中,都要把对应的值放在一起:
def train_test_split(x, y, test_pct):
data = zip(x, y) # 成对的对应值
train, test = split_data(data, 1 - test_pct) # 划分这个成对的数据集
x_train, y_train = zip(*train) # 魔法般的解压技巧
x_test, y_test = zip(*test)
return x_train, x_test, y_train, y_test
这样你就可以做一些类似下面这样的处理:
model = SomeKindOfModel()
x_train, x_test, y_train, y_test = train_test_split(xs, ys, 0.33)
model.train(x_train, y_train)
performance = model.test(x_test, y_test)
如果模型对训练数据是过拟合的,那么它在(完全划分开的)测试数据集上会有可能真的
表现得很不好, 换句话说,如果它在测试数据上表现良好,那么你可以肯定地说它拟合良
好而非过拟合。
然而在有些情况下这也可能会出错。
第一种情况是训练和测试数据集中的共有模式不能泛化到大型数据集上。
比如,假设数据集包括用户活跃度,每位用户每周一列。在此情形下,大多数用户会出现
在训练数据和测试数据中, 而且有些模型可能会学习识别用户而不是去发现涉及属性的联
系。这不是个太大的问题,尽管我曾经遇到过一次。
一个更大的问题是, 如果你划分训练集和测试集的目的不仅仅是为了判断模型,也是为了
在许多模型中进行选择。此时,尽管不是所有的模型都是过拟合的,但“选择在测试集上
表现最好的模型”是一种元训练(meta-training),会把测试集当作另一个训练集而运作。
(当然,在测试集上有最好表现的模型会在测试集上有持续的好表现。)
在这种情况下, 你应该把数据划分为三部分:一个用来建立模型的训练集,一个为在训练
好的模型上进行选择的验证集,一个用来判断最终的模型的测试集。








暂无数据