机器学习中级教程
在本教程中,您将了解什么是数据泄漏以及如何防止它。如果你不知道如何预防,泄漏会频繁出现,它会以微妙而危险的方式破坏你的模型。所以,这是数据科学家实践中最重要的概念之一。
正文
介绍
当您的训练数据包含有关目标的信息时,会发生数据泄漏,但当模型用于预测时,类似的数据将不可用。这将导致训练集(甚至可能是验证数据)的高性能,但该模型在做预测时的性能较差。
换句话说,泄漏会导致模型看起来很准确,直到你开始用模型做决策,然后模型变得非常不准确。
泄漏主要有两种类型:目标泄漏和训练试验污染。
目标泄漏
当预测值包含在预测时不可用的数据时,就会发生目标泄漏。重要的是要根据数据可用的时间或时间顺序来考虑目标泄漏,而不仅仅是功能是否有助于做出良好的预测。
举个例子会很有帮助。想象一下,你想预测谁会患肺炎。原始数据的前几行如下所示:
got_pneumonia | age | weight | male | took_antibiotic_medicine | … |
---|---|---|---|---|---|
False | 65 | 100 | False | False | … |
False | 72 | 130 | True | False | … |
True | 58 | 100 | False | True | … |
人们在感染肺炎后服用抗生素药物以恢复健康。原始数据显示,这些列之间有很强的关系,但在确定got_pneumonia
的数值后,服用抗生素的药物经常发生变化。这是目标泄漏。
该模型将看到,任何服用抗生素药物的值为False的人都没有肺炎。由于验证数据与训练数据来自同一个来源,因此该模式将在验证中重复,并且该模型将获得很好的验证(或交叉验证)分数。
但是,当该模型随后应用于现实世界时,它将非常不准确,因为当我们需要预测他们未来的健康状况时,即使是肺炎患者也不会接受抗生素治疗。
为防止此类数据泄漏,应排除在实现目标值后更新(或创建)的任何变量。
训练试验污染
如果不小心区分训练数据和验证数据,则会发生不同类型的泄漏。
回想一下,验证是用来衡量模型如何处理之前从未考虑过的数据。如果验证数据影响预处理行为,则可以以微妙的方式破坏此过程。这有时被称为训练试验污染。
例如,假设您在调用train_test_split()
之前运行预处理(比如为缺失值拟合插补器)。最终结果如何?你的模型可能会得到很好的验证分数,让你对它充满信心,但当你部署它来做决策时,它的表现很差。
毕竟,您将验证或测试数据中的数据合并到了如何进行预测中,因此,即使无法推广到新数据,也可能在特定数据上表现良好。当你进行更复杂的特征工程时,这个问题变得更加微妙(也更加危险)。
如果验证基于简单的训练测试分割,则从任何类型的拟合中排除验证数据,包括预处理步骤的拟合。如果使用scikit-learn
管道,这会更容易。使用交叉验证时,在管道内部进行预处理更为关键!
举例
在本例中,您将学习一种检测和消除目标泄漏的方法。
我们将使用有关信用卡应用程序的数据集,并跳过基本数据设置代码。最终的结果是,每个信用卡应用程序的信息都存储在一个数据集X中。我们将使用它来预测哪些应用程序在系列y中被接受。
import pandas as pd
# Read the data
data = pd.read_csv('../input/aer-credit-card-data/AER_credit_card_data.csv',
true_values = ['yes'], false_values = ['no'])
# Select target
y = data.card
# Select predictors
X = data.drop(['card'], axis=1)
print("Number of rows in the dataset:", X.shape[0])
X.head()
reports age income share expenditure owner selfemp dependents months majorcards active
0 0 37.66667 4.5200 0.033270 124.983300 True False 3 54 1 12
1 0 33.25000 2.4200 0.005217 9.854167 False False 3 34 1 13
2 0 33.66667 4.5000 0.004156 15.000000 True False 4 58 1 5
3 0 30.50000 2.5400 0.065214 137.869200 False False 0 25 1 7
4 0 32.16667 9.7867 0.067051 546.503300 True False 2 64 1 5
由于这是一个小数据集,我们将使用交叉验证来确保模型质量的准确测量。
from sklearn.pipeline import make_pipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
# Since there is no preprocessing, we don't need a pipeline (used anyway as best practice!)
my_pipeline = make_pipeline(RandomForestClassifier(n_estimators=100))
cv_scores = cross_val_score(my_pipeline, X, y,
cv=5,
scoring='accuracy')
print("Cross-validation accuracy: %f" % cv_scores.mean())
Cross-validation accuracy: 0.980292
根据经验,你会发现很少有模型在98%的时间内准确。这种情况经常发生,但我们应该更仔细地检查数据,以防目标泄漏。
以下是数据摘要,您也可以在“数据”选项卡下找到:
card
信用卡:1, 信用卡申请被接受,0, 不接受reports
报告:重大贬损报告的数量age
年龄:n岁加上一年的二十分之一income
收入:年收入(除以10000)share
份额:每月信用卡支出与年收入的比率expenditure
支出:每月平均信用卡支出owner
所有者:1如果拥有房屋,0如果出租selfempl
自营职业者:自营职业者为1,非自营职业者为0dependents
家属:1+家属人数month
月数:居住在当前地址的月数majorcards
:持有的主要信用卡数量active
活动:活动信用账户的数量
一些变量看起来可疑。例如,支出是指这张卡的支出还是申请前使用的卡的支出?
在这一点上,基础数据比较非常有用:
expenditures_cardholders = X.expenditure[y]
expenditures_noncardholders = X.expenditure[~y]
print('Fraction of those who did not receive a card and had no expenditures: %.2f' \
%((expenditures_noncardholders == 0).mean()))
print('Fraction of those who received a card and had no expenditures: %.2f' \
%(( expenditures_cardholders == 0).mean()))
Fraction of those who did not receive a card and had no expenditures: 1.00
Fraction of those who received a card and had no expenditures: 0.02
如上所示,所有没有收到卡的人都没有支出,而只有2%的收到卡的人没有支出。毫不奇怪,我们的模型似乎有很高的准确性。但这似乎也是target泄漏的一个例子,支出可能意味着他们申请的卡的支出。
由于share
部分由expenditure
决定,因此也应将其排除在外。active
和majorcards
变量不太清楚,但从描述来看,它们听起来令人担忧。在大多数情况下,如果您无法追踪到创建数据的人以获得更多信息,那么安全总比遗憾好。
我们将运行一个没有目标泄漏的模型,如下所示:
# Drop leaky predictors from dataset
potential_leaks = ['expenditure', 'share', 'active', 'majorcards']
X2 = X.drop(potential_leaks, axis=1)
# Evaluate the model with leaky predictors removed
cv_scores = cross_val_score(my_pipeline, X2, y,
cv=5,
scoring='accuracy')
print("Cross-val accuracy: %f" % cv_scores.mean())
Cross-val accuracy: 0.838510
这一准确度相当低,可能令人失望。然而,我们可以预计,在新的应用程序中使用该模型时,大约80%的时间是正确的,而泄漏模型可能会做得更糟(尽管它在交叉验证中的明显分数更高)。
结论
在许多数据科学应用中,数据泄漏可能是数百万美元的错误。仔细分离训练和验证数据可以防止列车测试污染,管道可以帮助实现这种分离。同样,谨慎、常识和数据探索的结合可以帮助识别目标泄漏。
接下来呢?
这似乎仍然很抽象。试着通过本练习中的示例来培养识别目标泄漏和训练测试污染的技能!
练习部分
大多数人觉得目标泄漏非常棘手,直到他们考虑了很长时间。
所以,在尝试考虑房价示例中的泄漏之前,我们先来看看其他应用中的一些示例。当你回到一个关于房价的问题时,事情会变得更加熟悉。
设置
下面的问题将为你的工作提供反馈。运行以下单元格设置反馈系统。
# Set up code checking
from learntools.core import binder
binder.bind(globals())
from learntools.ml_intermediate.ex7 import *
print("Setup Complete")
Setup Complete
第1步:鞋带的数据科学
耐克聘请你担任数据科学顾问,帮助他们节省鞋材费用。你的第一项任务是回顾一个模型,其中一名员工用来预测他们每个月需要多少鞋带。机器学习模型的特点包括:
- 当月(1月、2月等)
- 上个月的广告支出
- 截至本月初的各种宏观经济特征(如失业率)
- 他们本月最终使用的皮革数量
结果表明,如果你包括他们使用了多少皮革的特征,模型几乎是完全准确的。但如果你不考虑这一特征,它的准确度只能达到中等水平。你意识到这是因为他们使用的皮革数量是他们生产多少鞋子的完美指标,这反过来告诉你他们需要多少鞋带。
您认为皮革使用的功能是否构成数据泄漏的来源?如果你的答案是“视情况而定”,那它取决于什么?
在你考虑了你的答案之后,对照下面的解决方案检查一下。
这是一个棘手的问题,它取决于如何收集数据的细节(这在考虑泄漏时很常见)。你能在月初决定当月使用多少皮革吗?如果是这样,这没关系。但是,如果这是在一个月内确定的,那么当你做出预测时,你将无法获得它。如果您在月初有一个猜测,并且随后在该月内进行了更改,则该月的实际使用量不能用作功能(因为它会导致泄漏)。
第2步:归还鞋带
你有一个新想法。在你的鞋带模型中,你可以使用一个月前耐克订购的皮革数量(而不是他们实际使用的数量)作为预测指标。
这是否改变了您关于是否存在泄漏问题的答案?如果你回答“这取决于”,这取决于什么?
这可能没问题,但这取决于他们是先订购鞋带还是先订购皮革。如果他们先订购鞋带,当你预测他们的鞋带需求时,你将不知道他们订购了多少皮革。如果他们先订购皮革,那么当你订购鞋带时,你就有了这个值,你应该没问题。
第3步:用加密货币致富?
你为耐克省了很多钱,他们给了你奖金。祝贺你
你的朋友也是一名数据科学家,他说他建立了一个模型,可以让你把奖金变成数百万美元。具体来说,他的模型比预测时间提前一天预测新加密货币(比如比特币,但是更新的)的价格。他的计划是,只要模型显示加密货币(以美元为单位)的价格即将上涨,就购买加密货币。
他的模型中最重要的特征是:
- 货币的当前价格
- 过去24小时内售出的货币金额
- 过去24小时内货币价格的变化
- 过去1小时内货币价格的变化
- 过去24小时内新推文中提到货币的数量
在过去的一年里,以美元为单位的加密货币的价值上下波动超过100美元,但他的模型的平均误差不到1美元。他说,这证明了他的模型是准确的,你应该和他一起投资,在模型显示货币即将升值时购买货币。
他说得对吗?如果他的模型有问题,那是什么?
这里没有泄漏源。这些特征应该在您想要进行预测的时刻可用,并且在确定预测目标后,它们不太可能在训练数据中改变。但是,如果你不小心的话,他描述准确性的方式可能会产生误导。如果价格逐渐波动,今天的价格将准确预测明天的价格,但它可能不会告诉你现在是否是投资的好时机。例如,如果今天的价格为100,那么预测明天价格为100的模型可能看起来是准确的,即使它不能告诉你价格是从当前价格上涨还是下跌。更好的预测目标是第二天的价格变化。如果你能始终如一地预测价格是上涨还是下跌(以及上涨幅度),你可能会有一个成功的投资机会。
第4步:预防感染
一家提供医疗服务的机构希望预测哪些罕见手术的患者有感染风险,以便提醒护士在随访这些患者时要特别小心。
你想建立一个模型。建模数据集中的每一行都是接受手术的单个患者,预测目标是他们是否感染。
一些外科医生可能会以提高或降低感染风险的方式进行手术。但是,如何才能最好地将外科医生的信息整合到模型中呢?
你有个聪明的主意。
- 每个外科医生接受所有手术,并计算这些外科医生的感染率。
- 对于数据中的每个患者,找出外科医生是谁,并将该外科医生的平均感染率作为特征。
这是否会造成任何目标泄漏问题?是否会造成训练试验污染问题?
这会造成目标泄漏和训练测试污染的风险(尽管非常小心,您可能可以避免这两种情况)。
如果给定患者的结果影响了其外科医生的感染率,那么就存在目标泄漏,然后将其插入预测模型,以确定该患者是否感染。如果只使用我们预测的患者之前的手术来计算外科医生的感染率,就可以避免目标泄漏。在你的训练数据中计算每一次手术的数据可能有点棘手。
如果使用外科医生执行的所有手术(包括来自测试集的手术)来计算这一点,则也会出现列检污染问题。结果是,即使模型部署后不能很好地推广到新患者,您的模型在测试集上看起来也非常准确。这可能是因为外科医生风险特征考虑了测试集中的数据。测试集用于估计模型在看到新数据时的表现。因此,这种污染破坏了测试集的用途。
第5步: 房价
你将建立一个模型来预测房价。该模型将持续部署,以便在网站上添加描述时预测新房的价格。以下是四个可以用作预测指标的功能。
- 房屋面积(平方米)
- 同一街区房屋的平均售价
- 房子的经纬度
- 房子是否有地下室
您有历史数据来训练和验证模型。
以下哪项功能最有可能是泄漏源?
# Fill in the line below with one of 1, 2, 3 or 4.
# 用1,2,3,4 填写以下空白处
potential_leakage_feature = ____
# Check your answer
q_5.check()
2
是目标泄漏的来源。以下是对每个功能的分析:
- 房子出售后不太可能改变大小(尽管从技术上讲是可能的)。但通常情况下,当我们需要进行预测时,这些数据是可用的,并且在房屋出售后,这些数据不会被修改。所以很安全。
- 我们不知道何时更新的规则。如果在房屋出售后,原始数据中的字段被更新,并且房屋的出售被用于计算平均值,则构成目标泄漏的情况。在极端情况下,如果社区中只出售了一套房子,而这正是我们试图预测的房子,那么平均值将与我们试图预测的值完全相等。总的来说,对于销售较少的社区,该模型在培训数据上表现良好。但是,当你应用这个模型时,你预测的房子还没有售出,所以这个功能的工作原理与训练数据中的不一样。
- 这些不会改变,在我们想要做出预测的时候可以使用。所以这里没有目标泄漏的风险。
- 这也不会改变,在我们想要做出预测的时候,它是可用的。所以这里没有目标泄漏的风险。
结论
泄漏是一个棘手而微妙的问题。如果你学会了这些例子中的问题,你应该感到自豪。
现在,你有了制作高精度模型的工具,并学习应用这些模型解决实际问题时出现的最困难的实际问题。
在积累知识和经验方面仍有很大的空间。尝试一场比赛或查看我们的数据集来练习你的新技能。
再次祝贺你!
答案
potential_leakage_feature = 2