来源:老师 - kesci.com,微信公众号:Kaggle竞赛宝典
原文链接:99%的人都会用错或者不会看的N折验证
点击以上链接👆 不用配置环境,直接在线运行
做实际比赛和机器学习项目, 很多朋友都会经常遇到线下线上不一致的情况,排除一些特殊的情况,例如问题没法预测,不存在潜在pattern的情况等,我敢说99%的人都不会看N折验证的结果。
你可能会吐槽我,等等,你先看我举一个简单的例子。
假设我有一个项目,例如最近的“智慧海洋建设”的比赛,它的评估指标是三个类的F1的平均,这个时候我们有两个模型,都使用相同的参数,每隔50次的展示一下结果,
lgb_model.fit(train_x, train_y, eval_set=eval_set, eval_metric=f1_macro, early_stopping_rounds=150, verbose=50)
其中第一个模型的线下验证结果为:
[50] valid_0's f1_macro: 0.92763
[100] valid_0's f1_macro: 0.931709
[150] valid_0's f1_macro: 0.934416
[200] valid_0's f1_macro: 0.931428
[250] valid_0's f1_macro: 0.927119
[300] valid_0's f1_macro: 0.927119
Early stopping, best iteration is:
[150] valid_0's f1_macro: 0.934416
其中第二个模型的线下验证结果为:
[50] valid_0's f1_macro: 0.92763
[100] valid_0's f1_macro: 0.931709
[150] valid_0's f1_macro: 0.932416
[200] valid_0' s f1_macro: 0.933428
[250] valid_0's f1_macro: 0.932119
[300] valid_0's f1_macro: 0.932119
[350] valid_0's f1_macro: 0.931119
Early stopping, best iteration is:
[222] valid_0's f1_macro: 0.93390
99%的朋友在碰到这种情况的时候,会直接选择第一个模型,因为它能达到的f1_macro可以达到0.934416,而几乎不会去看后面的结果,如果我们细细看的话,我们就会发现,第二个模型相较于第一个模型稳定很多,很多时候提交第二个模型的结果时,线上成绩也会相对好一些,为什么呢?
本质问题是,我们在验证的时候已经作弊了!为什么呢?
因为我们是在已知label的情况下寻找最佳停止的位置,也就是说我们的停止的位置就是在其他参数固定下最佳的停止迭代次数,这在实际情况下怎么可能呢?
很多朋友玩比赛的时候肯定会有一种体会,有的时候没思路,又不想浪费时间,就会尝试用不同的迭代次数来提交,尤其和上面第一种情况一样,不同的迭代次数影响还很大,这其实就是线下验证作弊了,等于说提交了300多次的结果并且得到了实时的反馈,然后你选择了最佳的结果作为你的验证结果,这在真实比赛中完全不可能有那么多的提交机会。而第二个模型的结果在很多次提交中都比第一个结果的要好,尤其是后面每次迭代的结果基本都比第一个结果的分数高。所以大概率第二个结果的提交会比第一个好,这也是为什么实践中用第二个模型的预测结果提交更靠谱的原因。
这个时候很多朋友肯定会说,我实战中基本都是线下提升了,线上就提升了的啊,这个没太大问题,毕竟上面描述的两种验证结果只有指标相对敏感的时候容易出现一点,很多时候还是很少会出现这种情况的,这也是为什么大多数时候大家线下提升了,线上往往也会提升的原因。
还有一种场景,很多人也发现了(参考天池论坛),在海洋比赛中,五折的效果比10折或者8折差了很多,10折或者8折在初赛或者复赛的时候90%的概率比五折的效果要好,为什么呢?
-
因为用了更多的数据
-
因为运气
-
好像在这题中是这样的
-
这是我发现的tricks
其实这个很容易,本来我们的验证框架不对,只是很多时候我们发现五折线下涨,线上大概率也涨,所以就懒得寻找最优N了,很多时候也就是没什么思路的时候随机改一下N, 然后线上提交看看效果, 那么线下怎么寻找一种靠谱的验证方式来帮助我们寻找最优的N呢?
- 改成两层的!
def model(X,y):
model = NFoldModel(X,y) # N折训练,得到N个模型
def FiveFold_Validation(X,y):
model = first_model()
for tr_ind, val_ind in KFole(X,y):
X_tr, X_val, y_tr, y_val = X[tr_ind], X[val_ind], y[tr_ind], y[val_ind]
model = model(X_tr, y_tr)
y_pred = model.predict(X_val)
score(y_pred,y_val)
其中第一层和平时一样,只是第二层模型由之前的单模变成了N折的,这个时候第一层N折训练得到的N折模型再对验证集预测得到的结果,这个时候在看最终五折的结果,就会一目了然。此外,你还会发现另外一个明显的优点,验证的结果线上和线下的gap相较于之前的也变小了。
拿海洋赛来举例,线下按上面的方法一试就可以发现了7-10折的效果线下在第二种验证方式的情况下相较于五折基本每次都要好一些。