对抗验证:验证训练集和测试集的数据分布是否⼀致
1.1 对抗验证的简介:
  通常情况下,我们⼀般都会使⽤交叉验证来作为评估模型的标准,来选择我们最后的模型。但是在⼀些数据挖掘竞赛中,数据集⼀般分为训练集合测试集,国内⽐赛可能根据⽐赛阶段划分多个测试集,由于数据集采样和分布的原因导致训练集和线上测试集可能存在分布不⼀致的情况,这时候CV⽆法准确的评估模型在测试集上的效果,导致线上线下不统⼀,分数上不去。⽽缓解这⼀问题的⿊科技,就是对抗验证Adversarial validation。
  样本分布变化主要体现在训练集和测试集的数据分布存在差异。⽐如,在化妆品或者医美市场,男性的⽐例越来越多。基于过去的数据构建的模型,渐渐不适⽤于现在。 
⽐如我们现在要对淘宝⽤户的购买⾏为进⾏推荐或者预测。我们的训练数据集中⽤户的年龄分布⼤概在18~25岁,⽽我们的测试集中主要是70岁以上的⽼⼈组成。这时我们的数据样本分布就发⽣了变化。
训练集与测试的不⼀致问题是我们经常⾯临的问题,在互⾦领域,市场环境变化,准⼊策略,额度策略的调整,会导致训练样本在时间维度上存在差异,因此在利⽤⼤规模样本,或者长期限样本来训练模型时,必然会存在训练集与测试集(或者当前线上打分模型)产⽣偏差,这种现象在模型指标上的表现就是训练集,
验证集上的KS/AUC想对较⾼,测试集上天然会存在decay的现象。⾯对这种情况,不能把原因单纯的归结为过拟合,⽽使劲地去改善这种表⾯的过拟合现象,也需要考虑上述⼈变化的原因。
训练集与测试集差异明显的典型例⼦很容易发⽣在Kaggle⽐赛,或者国内⾼⽔平的⽐赛上,⽐赛前期显⽰的都是在公榜上成绩,最后的评判的却是的额外的私榜上,就会产⽣很⼤喜闻乐见的地震, shake up。
Adversarial validation:⽤来验证train_test 数据分布是否⼀致;出影响数据分布不⼀致的特征;从训练集中出⼀部分跟test类似的数据。
Adversarial validation,⽹上的翻译是对抗验证,但是当我看完内容之后其实是没有发现太明显的对抗痕迹,还是⾼攀得起的,步骤如下:
1. 构建⼀个样本的分类器,该⼆分类器的任务⽤于区分样本来源于训练集,还是测试集。因此,需要为原始数据新增⼀个标签列,将训
练集中的样本标记为0,测试集中的样本标记为1,样本的特征是数据中已有的特征,或者衍⽣的新特征,⽣成新的训练数据集;
2. 将新的训练数据集进⾏划分,保留部分样本作为该样本分类任务的测试集,利⽤分类算法(LightGBM)
等对数据集进⾏训
练,AUC作为模型指标;
3. 在测试集中进⾏验证,如果模型效果AUC在0.5左右,说明该样本分类模型⽆法区分样本来源训练集,还是测试集,说明原始数
据中训练集,测试集分布是⼀致的;如果AUC较⼤,如0.9, 说明样本分类器很容易区分样本,间接说明训练集与测试集存在很⼤差异;这就是⽤来验证的
4. 根据第3步的结论,对于分布⼀致的,正常对⽬标任务训练即可。对于分布不⼀致的,可以继续进⾏样本挑选的尝试。利⽤上述样本分
类器模型,对原始的训练集进⾏打分预测,并将样本按照模型分从⼤到⼩排序,模型分越⼤,说明与测试集越接近,那么取训练集中的TOP N 的样本作为⽬标任务的验证集,这样即可将原始的样本进⾏拆分得到训练集,验证集,测试集。那么线上模型验证时,在这样的数据上调参等得到模型,如果在验证集上效果稳定,那么应⽤在测试集上,⼤概率结果是⼀致的
如此,完成了local CV的构建。有了上述的思路,可以做进⼀步的扩展(在可容忍的模型误差范围内),利⽤样本分类模型,挑选与测试集相近的训练集,做样本的反向选择,挑选合适训练样本进⾏模
型训练。
2.1 代码:
import pandas as pd
import numpy as np
from sklearn.datasets import load_irisston
del_selection import train_test_split
boston=load_boston()
data=pd.DataFrame(boston.data,columns=boston.feature_names)
tar=pd.DataFrame(boston.target,columns=['predict'])
at([data,tar],axis=1)
df
x_train,x_test,y_train,y_test=train_test_split(data,tar,test_size=0.3,random_state=1)
# 开始给训练集和测试集打上标签。
x_train['target']=0
x_test['target']= 1
#将训练集和测试集合并
at([x_train,x_test],axis=0)
#取出train_label,⽅便后⾯巡礼N
train_label=data['target']
data.drop(['target'],axis=1,inplace=True)
#开始验证训练集和测试集是否⼀样,如果越接近0.5,就说明⼀样
del_selection import StratifiedKFold
import lightgbm as lgb
train_data=data
evals_result={}
params = {
'booster': 'gbdt',
'objective': 'binary',
'metric': 'auc',
'num_leaves': 5,
'min_data_in_leaf': 91,
'max_bin': 205,
'max_depth': 8,
valid from是什么意思'num_leaves':20,
'max_bin':50,
"learning_rate": 0.01,
'feature_fraction': 0.6,
"bagging_fraction": 1.0,  # 每次迭代时⽤的数据⽐例
'bagging_freq': 45,
'min_split_gain': 1.0,
'min_child_samples': 10,
'lambda_l1': 0.3, 'lambda_l2': 0.6,
'n_jobs': -1,
'silent': True,  # 信息输出设置成1则没有信息输出
'seed': 1000,
}
kf=StratifiedKFold(n_splits=5,shuffle=True,random_state=123)  #类别交叉严重
x,y=pd.DataFrame(train_data),pd.DataFrame(train_label)  #将数据dataframe化,后⾯进⾏iloc 等选项
for i,(train_index,valid_index) in enumerate(kf.split(x,y)): #这⾥需要输⼊y
print("第",i+1,"次")
x_train,y_train=x.iloc[train_index],y.iloc[train_index]
x_valid,y_valid=x.iloc[valid_index],y.iloc[valid_index]  #取出数据
lgb_train = lgb.Dataset(x_train, y_train,silent=True)
lgb_eval  = lgb.Dataset(x_valid, y_valid, reference=lgb_train,silent=True)
gbm = ain(params, lgb_train, num_boost_round=10000, valid_sets=[lgb_train, lgb_eval],verbose_eval=100,
early_stopping_rounds=200,evals_result=evals_result)
#varbose_eval 迭代多少次打印  early_stopping_rounds:有多少次分数没有提⾼就停⽌
#categorical_feature:lightgbm可以处理标称型(类别)数据。通过指定'categorical_feature' 这⼀参数告诉它哪些feature是标称型的。#它不需要将数据展开成独热码(one-hot),其原理是对特征的所有取值,做⼀个one-vs-others,从⽽出最佳分割的那⼀个特征取值#bagging_fraction:和bagging_freq同时使⽤可以更快的出结果
vaild_preds = gbm.predict(x_valid, num_iteration=gbm.best_iteration)
#对测试集进⾏操作
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
feature_imp = pd.DataFrame(sorted(zip(gbm.feature_importance(),lumns), reverse=True), columns=['Value','Feature'])
plt.figure(figsize=(20, 50))
sns.barplot(x="Value", y="Feature", data=feature_imp.sort_values(by="Value", ascending=False))
plt.title('LightGBM Features (avg over folds)')
plt.tight_layout()
plt.show()
#可以看到,训练集的AUC⼤概在0.5左右,测试集的AUC在0.35左右,(都没有偏差0.2以上)训练集和测试集的数据分布是⼤致⼀样的. #我们还可以看到分布不⼀样的⼏个特征如上图
#我们可以出与测试集分布相似的数据进⾏数据验证 Or 训练
#
# 开始给训练集和测试集打上标签。
x_train['target']=0
x_test['target']= 1
#将训练集和测试集合并
at([x_train,x_test],axis=0)
#取出train_label,⽅便后⾯巡礼N
train_label=data['target']
data.drop(['target'],axis=1,inplace=True)
lgb_train = lgb.Dataset(data,train_label,silent=True)
gbm = ain(params, lgb_train, num_boost_round=10000,verbose_eval=100)
test_pre = gbm.predict(train_data, num_iteration=gbm.best_iteration)
# 提取出训练集上,样本是测试集的概率
x_train['is_test_prob'] = test_pre[:len(x_train)]
#x_train['label']=train_label
# 根据概率排序
x_train= x_train.sort_values('is_test_prob',ascending=False).reset_index(drop=True) # 将概率最⼤的20%作为验证集
x_train= x_train.iloc[:int(0.5 * len(x_train)), ]
x_train.drop('is_test_prob', axis=1, inplace=True)
#x_train.drop('target', axis=0, inplace=True)
#这样就拿到了跟测试集⼀样的验证集(训练集)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。