看了一下,没有关于Data leakage相关的blog,自己写吧。。
Kaggle课程上说的有点迷糊,先来个例子,直观。
是否得肺炎 | 年龄 | 体重 | 性别 | 是否服用抗生素 |
---|---|---|---|---|
False | 65 | 100 | 男 | False |
True | 72 | 130 | 女 | True |
True | 58 | 100 | 男 | True |
这里就能看出点问题了,原始数据中,得肺炎和服用抗生素有很强的相关性,人们在患肺炎后服用抗生素是为了恢复健康,但是在确定得肺炎之后,是否服用抗生素经常被更改,这就是目标泄露。
从原始数据中能看到,任何不服用抗生素的人都没有患肺炎,验证数据和训练数据来自同一个源,所以模式会在验证中重复,所以模型交叉验证分数会很高。
但是如果将模型置于实际生活中,准确率会非常低,因为我们需要对他们未来的健康进行预测时,他们可能不会使用抗生素。
排除我们预测点之后的任何变量,打个比方,服用抗生素应该是在确定患肺炎之后,那我们预测患者是否得肺炎的时候,是否服用抗生素这一变量我们就不能使用。
简单的来讲,就是使用train_test_split()
之前,就对数据进行预处理了,如fit_transformed, imputer
来自于Kaggle信用卡应用数据集。(数据集在Kaggle上可找到)
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.980283
根据经验,模型能达到98%非常少见,所以应该仔细检查数据。
数据摘要:
简单观察发现疑点,就是expenditure,支出是指此卡的平均支出,还是未申请此卡前的信用卡平均支出。
写代码来查看一下,什么样的人有支出,什么样的没有。
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
运行一个排除['expenditure', 'share', '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.830170
虽然准确率低了些,但是也比不处理之前的模型要好。
数据泄露在许多数据科学中,是个很严重的问题,仔细分离Train-Valid数据可以有效防止train-test contamination
,可以用Pipeline来轻松实现。
同样,谨慎,常识,数据探索可以帮助识别目标泄露。