本文是《机器学习宝典》第 6 篇,读完本文你能够掌握机器学习中数据泄露问题。
读完分类与回归算法的评估指标、排序算法的评估指标以及机器学习模型的离线评估方法之后,你已经知道了在机器学习中的该使用什么指标来评估模型以及使用什么方法来评估模型,但是在现实生活中评估模型时经常会遇到一个问题:数据泄露(data leakage),这里我们来对数据泄露做一个解读。
什么是数据泄露
先举个贴近生活的例子,你作为一名优秀的算法工程师,你的志向是去通过机器学习算法解决生活中的很多实际问题。在解决一个二分类问题时,你为了充分使用数据集,使用交叉验证的方法,训练了一个模型,发现它在测试集上的AUC指标 0.99,这时你心里美滋滋地想着:开发出了这么牛逼的模型,今年的年终奖应该能拿到手软了吧。紧接着系统工程师将这个模型进行工程化,部署到生产环境中,开始真正解决实际的业务问题。当你正在给同事吹嘘模型多么牛逼,多么吊炸天的时候,模型在生产环境中的效果表现数据出来了,你看完后,顿时双腿一软,要不是同事扶着你,你直接瘫倒在地。
出现上面这种模型在离线评估时效果好,线上效果不好的原因有很多种,其中有一个经常会碰到的原因是:数据泄露(data leakage),有时也叫做泄露、穿越等。它说的是用于训练机器学习算法的数据集中包含了一些将要预测的事务的东西(when the data you are using to train a machine learning algorithm happens to have the information you are trying to predict),也就是说测试数据中的一些信息泄露到了训练集中。这里说的信息是指关于目标标签或者在训练数据中可用但在真实世界中却不可用、不合法的数据。
数据泄露一般以非常微妙和难以察觉的方式发生。当数据泄露发生时,会导致模型离线的评估结果“虚高”。“虚高”的意思是说你在离线阶段评估模型的时候,在测试集上表现很好,但是等真正部署到生产环境解决实际业务问题的时候,效果表现会非常的差。也就是说,离线评估时高估了模型的能力。
关于数据泄露的一些具体实例
上面虽然说了数据泄露的定义,但是太抽象了,这里举几个实例来说明下数据泄露。比较容易理解的的一个泄露实例:如果训练数据中包含了测试数据,这样会导致模型过拟合。还有一个比较容易理解的泄露实例:如果将预测目标作为模型的特征,这样模型的结论基本上就类似于“苹果是苹果”。意思是说如果一个物品被贴上了苹果的标签,那么模型预测它是苹果。我们再来看一些在KDD比赛中更加微妙的泄露的例子。
预测潜在顾客是否会银行开户
在预测潜在顾客是否会在银行开账户的时候,使用的一个特征叫做:account number,也就是账号。很明显,只有开过户的顾客这个字段才会有值。在训练时没有任何问题,但是在实际进行预测时,对所有顾客来说,这个特征都是空的,因为在预测之前你是不知道顾客的账户是多少,如果说在预测之前你已经知道了顾客的账户,那预测模型还有什么用呢?
预测用户是否会离开网站
在零售网站中,预测用户浏览当前页面之后接下来是离开网站或是浏览另一个新页面时,有一个涉及数据泄露的特征叫做:session length,也就是用户在访问网站时浏览的页面总数。这个特征包含了未来的信息,即用户将进行多少次访问。有一种解决办法是将 session length 替换为 page number in session,即session中截止到目前为止页面浏览总数。
预测用户是否会购买商品
在电商网站中,经常会预测给用户曝光商品后,是否会购买的问题。很明显,在这个问题中,商品的好评率是非常重要的因素,一般训练时都是使用过去的数据来生成模型,比如使用过去一周的数据,在为训练数据生成商品的好评率时,如果使用该商品当前时间的好评率,这会造成这个特征包含了未来的信息,所以应该使用在曝光时该商品的好评率。举例来说,在2018年10月10日22分30秒给用户u曝光了一件商品i,最终用户u购买了该商品,在曝光时该商品的好评率是99%,一周后,也就是2018年10月17日22分30秒,该商品的好评率是86%,这时候在使用前面的数据构建训练样本时,其中商品好评率这个特征的取值应该是曝光时的99%,而不是现在的86%。
预测病人的患病情况
在开发一个用来诊断特定疾病的模型,现有的患者训练集中包含了一个病人是否为该疾病做过手术的特征。很明显,使用这个特征可以极大地提高预测的准确性,但是这明显存在数据泄露,因为在病人的诊断结果没有出来之前,这个特征无法知道。
另外一个与之相关的例子是患者ID,由于患者ID可能根据特定的诊断路径分配。换句话说,如果是去看专家的结果,ID可能会有所不同,因为最初的医生认定可能出现疾病。
数据泄露的类型介绍
我们可以将数据泄露分为两大类:训练数据泄露和特征泄露。训练数据泄露通常是测试数据或者未来的数据混合在了训练数据中,特征泄露是指特征中包含了关于真实标签的信息。
导致训练数据泄露可能有以下几种情况:
- 在进行某种预处理时是使用整个数据集(训练集和测试集)来计算的,这样得到的结果会影响在训练过程中所看到的内容。这可能包括这样的场景:计算参数以进行规范化和缩放,或查找最小和最大特征值以检测和删除异常值,以及使用变量在整个数据集中的分布来估计训练集中的缺失值或执行特征选择。
- 在处理时间序列数据时,另一个需要注意的关键问题是,未来事件的记录意外地用于计算特定预测的特性。我们看到的会话长度示例就是其中的一个实例。
导致特征泄露可能有以下几种情况:
- 删除了一些不合法的特征,但是忽略删除了包含相同或类似信息的特征(例如前面例子中删除了病人是否做过手术这个特征,但是没有删除患者ID)
- 在某些情况下,数据集记录被有意随机化,或者某些字段被匿名化,这些字段包含关于用户的特定信息,比如用户的名字、位置等等。根据预测任务的不同,取消这种匿名化可以揭示用户或其他敏感信息,而这些信息在实际使用中并不合法。
检测数据泄露
当我们了解了什么是数据泄露了之后,下一步来看下如何检测数据泄露。
在构建模型之前,我们可以先对数据进行一些探索分析。例如,寻找与目标标签或者值高度相关的特征。比如在医学诊断的例子中,病人是否为该疾病做过手术这个特征与最终是否患病的相关性非常高。
当构建模型之后,我们可以检查下模型中权重极高的特征是否存在泄漏的情况。或者构建模型之后,发现模型的效果好到不可思议,这时候需要考虑下是否发生了数据泄露。
另一个更可靠的检查泄漏的方法是,对经过训练的模型进行有限的实际部署,看看模型的训练时的性能与真实环境的表现之间是否有很大的差别。但是如果差别比较大的话,也有可能是是过拟合造成的。
修复数据泄露
如果检测到发生了数据泄露,那么如何修复呢?
首先,在进行数据预处理时,不应该使用整个数据集来计算,而是应该使用划分后的训练集来生成。
如果在处理时间序列问题时,一定要确保关联特征时的时间戳与发生时间一致,这样能避免训练数据中出现来自未来的信息。
另外,针对一些与预测目标相关性特别高或者模型中权重特别高的特征,一定要好好地检查下是否发生了数据泄露,如果确实是,那么一定要剔除。
练习题
看完这篇文章,我们来做一道练习题来检验下学习成果:
- 思考下,当你训练了一个模型之后,如何快速判断这个模型是否出现了数据泄露的情况呢?
参考: