Target leakage(目标泄露),Train-Test Contamination

Data leakage

  • Target leakage
    • 如何避免?
  • Train-Test Contamination
  • 例子:如何去除Target leakage
  • 总结

看了一下,没有关于Data leakage相关的blog,自己写吧。。

Target leakage

Kaggle课程上说的有点迷糊,先来个例子,直观。

是否得肺炎 年龄 体重 性别 是否服用抗生素
False 65 100 False
True 72 130 True
True 58 100 True

这里就能看出点问题了,原始数据中,得肺炎和服用抗生素有很强的相关性,人们在患肺炎后服用抗生素是为了恢复健康,但是在确定得肺炎之后,是否服用抗生素经常被更改,这就是目标泄露
从原始数据中能看到,任何不服用抗生素的人都没有患肺炎,验证数据和训练数据来自同一个源,所以模式会在验证中重复,所以模型交叉验证分数会很高。
但是如果将模型置于实际生活中,准确率会非常低,因为我们需要对他们未来的健康进行预测时,他们可能不会使用抗生素。

如何避免?

排除我们预测点之后的任何变量,打个比方,服用抗生素应该是在确定患肺炎之后,那我们预测患者是否得肺炎的时候,是否服用抗生素这一变量我们就不能使用。
在这里插入图片描述

Train-Test Contamination

简单的来讲,就是使用train_test_split()之前,就对数据进行预处理了,如fit_transformed, imputer

例子:如何去除Target leakage

来自于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%非常少见,所以应该仔细检查数据。

数据摘要:

  • card: 1 接受信用卡为1,不接受为0
  • reports: 主要贬损报告数量
  • age: 年龄,n岁加上一年的十二分之一
  • income: 年收入除以10,000
  • share: 每个月信用卡支出与收入的比率
  • expenditure: 平均每月信用卡支出
  • owner: 有房屋为1,租房为0
  • selfempl: 如果是自雇人员为1,否则为0
  • dependents: 1 + 家属人数
  • months: 在当前住址居住的月数
  • majorcards: 持有主要信用卡数目
  • active: 活动信用账户的数量

简单观察发现疑点,就是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
  • 我们发现,没有收到卡的人都没有支出,但是有2%的人收到卡,但是也没有支出。
  • 那我们就知道了,支出是指申请的卡上的支出,有目标泄露风险。
  • 由于份额(share)由支出(expenditure)决定,所以应该排出去。
  • 然后active和majorcards,不太清楚,但是听起来有点担心,所以也排除出去, 本着宁可所杀一百不能放过一个的原则,来试一试。

运行一个排除['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来轻松实现。
同样,谨慎,常识,数据探索可以帮助识别目标泄露。

你可能感兴趣的:(Kaggle)