(一)机器学习避坑指南:训练集/测试集分布一致性检查

https://blog.csdn.net/jpld/article/details/111659837

工业界有一个大家公认的看法,“数据和特征决定了机器学习项目的上限,而算法只是尽可能地逼近这个上限”。在实战中,特征工程几乎需要一半以上的时间,是很重要的一个部分。缺失值处理、异常值处理、数据标准化、不平衡等问题大家应该都已经手到擒来小菜一碟了,本文我们探讨一个很容易被忽视的坑:数据一致性。

众所周知,大部分机器学习算法都有一个前提假设:训练数据样本和位置的测试样本来自同一分布。如果测试数据的分布跟训练数据不一致,那么就会影响模型的效果。

在一些机器学习相关的竞赛中,给定的训练集和测试集中的部分特征本身很有可能就存在分布不一致的问题。实际应用中,随着业务的发展,训练样本分布也会发生变化,最终导致模型泛化能力不足。

下面就向大家介绍几个检查训练集和测试集特征分布一致性的方法:

KDE(核密度估计)分布图
核密度估计(kernel density estimation)是在概率论中用来估计未知的密度函数,属于非参数检验方法之一,通过核密度估计图可以比较直观的看出数据样本本身的分布特征。

seaborn中的kdeplot可用于对单变量和双变量进行核密度估计并可视化。

看一个小例子:

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
train_set=pd.read_csv(r'D:\...\train_set.csv')
test_set=pd.read_csv(r'D:\...\test_set.csv')
plt.figure(figsize=(12,9))
ax1 = sns.kdeplot(train_set.balance,label='train_set')
ax2 = sns.kdeplot(test_set.balance,label='test_set')

KS检验(Kolmogorov-Smirnov)
KS检验是基于累计分布函数,用于检验一个分布是否符合某种理论分布或比较两个经验分布是否有显著差异。两样本K-S检验由于对两样本的经验分布函数的位置和形状参数的差异都敏感,所以成为比较两样本的最有用且最常用的非参数方法之一。

我们可以使用 scipy.stats 库中的ks_2samp,进行KS检验:

from scipy.stats import ks_2samp
ks_2samp(train_set.balance,test_set.balance)
ks检验一般返回两个值:第一个值表示两个分布之间的最大距离,值越小即这两个分布的差距越小,分布也就越一致。第二个值是p值,用来判定假设检验结果的一个参数,p值越大,越不能拒绝原假设(待检验的两个分布式同分布),即两个分布越是同分布。

Ks_2sampResult(statistic=0.005976590587342234, pvalue=0.9489915858135447)
最终返回的结果可以看出,balance这个特征在训练集测试集中服从相同分布。

对抗验证(Adversarial validation)
除了 KDE 和 KS检验,目前比较流行的是对抗验证,它并不是一种评估模型效果的方法,而是一种用来确认训练集和测试集的分布是否变化的方法。
具体做法:
1、将训练集、测试集合并成一个数据集,新增一个标签列,训练集的样本标记为 0 ,测试集的样本标记为 1 。
2、重新划分一个新的train_set和test_set(区别于原本的训练集和测试集)。
3、用train_set训练一个二分类模型,可以使用 LR、RF、XGBoost、 LightGBM等等,以AUC作为模型指标。
4、如果AUC在0.5左右,说明模型无法区分原训练集和测试集,也即两者分布一致。如果AUC比较大,说明原训练集和测试集差异较大,分布不一致。
5、利用第 2 步中的分类器模型,对原始的训练集进行打分预测,并将样本按照模型分从大到小排序,模型分越大,说明与测试集越接近,那么取训练集中的 TOP N 的样本作为目标任务的验证集,这样即可将原始的样本进行拆分得到训练集,验证集,测试集。

除了确定训练集和测试集特征分布一致性,对抗验证还可以用来做特征选择。大家感兴趣的话可以给个赞+在看,下一讲《特征选择》,我们用实例来看看对抗验证的具体用法和效果。
————————————————
版权声明:本文为CSDN博主「机器学习算法与Python实战」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jpld/article/details/111659837

(二)机器学习中的对抗验证

https://blog.csdn.net/qq_39783265/article/details/104848263

对抗验证
交叉验证(Cross Validation)是常用的一种用来评估模型效果的方法。

当样本分布发生变化时,交叉验证无法准确评估模型在测试集上的效果,这导致模型在测试集上的效果远低于训练集。

通过本文,你将通过一个kaggle的比赛实例了解到,样本分布变化如何影响建模,如何通过对抗验证辨别样本的分布变化,以及有哪些应对方法。

直接给链接:https://zhuanlan.zhihu.com/p/93842847

在此之前,不过不懂AUC,请学习下面链接:
https://www.zhihu.com/question/39840928/answer/241440370

贴上自己的代码,以便于理解:

##df_train:用给的训练集
##df_test:用测试机当验证集
df_train = train_lables
df_test = test_lables
# 定义新的Y
df_train['Is_Test'] = 0
df_test['Is_Test'] = 1
# 将 Train 和 Test 合成一个数据集。
df_adv = pd.concat([df_train, df_test])
# features:训练时所用到的特征
X = df_adv[features]
y = df_adv['Is_Test']
1
2
3
4
5
6
7
8
9
10
11
12
模型训练
# 定义模型参数
params = {
    'boosting_type': 'gbdt',
    'colsample_bytree': 1,
    'learning_rate': 0.1,
    'max_depth': 5,
    'min_child_samples': 100,
    'min_child_weight': 1,
    'min_split_gain': 0.0,
    'num_leaves': 20,
    'objective': 'binary',
    'random_state': 50,
    'subsample': 1.0,
    'subsample_freq': 0,
    'metric': 'auc',
    'num_threads': 8
}
cv_pred = []
best_loss = []
test_prob = 0
n_splits = 5
skf = StratifiedKFold(n_splits=n_splits, shuffle=True, random_state=42)
for index, (train_idx, test_idx) in enumerate(fold.split(X, y)):
    lgb_model = lgb.LGBMClassifier(**params)
    train_x, test_x, train_y, test_y = X.loc[train_idx], X.loc[test_idx], y.loc[train_idx], y.loc[test_idx]
    eval_set = [(test_x, test_y)]
    lgb_model.fit(train_x, train_y, eval_set = eval_set, eval_metric='auc',early_stopping_rounds=100,verbose=None)
    best_loss.append(lgb_model.best_score_['valid_0']['auc'])
    print(best_loss, np.mean(best_loss))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
AUC结果:
[0.5548410714285714] 0.5548410714285714
[0.5548410714285714, 0.5788339285714286] 0.5668375
[0.5548410714285714, 0.5788339285714286, 0.5695142857142858] 0.5677297619047619
[0.5548410714285714, 0.5788339285714286, 0.5695142857142858, 0.5460357142857143] 0.56230625
[0.5548410714285714, 0.5788339285714286, 0.5695142857142858, 0.5460357142857143, 0.5811589285714286] 0.5660767857142857

此方法用来评价训练集与测试集分布是否一致,以防止新的测试集出现,导致崩盘的现象
————————————————
版权声明:本文为CSDN博主「猫爱吃鱼the」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39783265/article/details/104848263

(三)还在用交叉验证?试试Kaggle大牛们常用的方法——对抗验证

https://zhuanlan.zhihu.com/p/93842847

交叉验证(Cross Validation)是常用的一种用来评估模型效果的方法。

当样本分布发生变化时,交叉验证无法准确评估模型在测试集上的效果,这导致模型在测试集上的效果远低于训练集。

通过本文,你将通过一个kaggle的比赛实例了解到,样本分布变化如何影响建模,如何通过对抗验证辨别样本的分布变化,以及有哪些应对方法。

本篇文章完整代码: https://github.com/Qiuyan918/Adversarial_Validation_Case_Study/blob/master/Adversarial_Validation.ipynb

目录

  • 什么是样本分布变化
  • 为什么样本分布变化的时候,交叉验证不适用?
  • 什么是对抗验证?
  • 分布变化时,有哪些优于交叉验证的方法?
  • Kaggle比赛实例(lightgbm模型;Python)

1 什么是「样本分布变化」?

在真实的业务场景中,我们经常会遇到「样本分布变化」的问题。

主要体现在训练集和测试集的分布存在的差异。比如,在化妆品或者医美市场,男性的比例越来越多。基于过去的数据构建的模型,渐渐不适用于现在。

2 为什么「样本分布变化」的时候,交叉验证不适用?

当我们要做一个模型,来预测人们在超市的消费习惯。

我们的训练样本主要是18岁至25岁的年轻人构成,而测试样本主要是70岁以上的老人组成。这时样本分布就发生了变化。

图1 训练样本和测试样本分布偏差

这种情况下,使用交叉验证,无法准确评估模型的效果。原因是,交叉验证的验证集和测试集不够相似。

交叉验证中,每一折的验证集都是从训练集随机抽取的。随机抽取的验证集的分布和整体的训练集是相同的,也就意味着每一折的验证集都和测试集的分布存在较大的差异。

所以在样本分布变化时,通过交叉验证的方式构建的模型,在测试集上的表现,相较于训练集,通常会打折扣。稍后我们会通过一个实例来确认这一点。

3 什么是对抗验证(Adversarial Validation)?

对抗验证(Adversarial Validation),并不是一种评估模型效果的方法,而是一种用来确认训练集和测试集的分布是否变化的方法。

它的本质是构造一个分类模型,来预测样本是训练集或测试集的概率。

如果这个模型的效果不错(通常来说AUC在0.7以上),那么可以说明我们的训练集和测试集存在较大的差异。

仍然以「预测人们在超市的消费习惯」为例。因为训练集主要是18岁-25岁的年轻人,测试集主要是70岁以上的老人,那么通过「年龄」,我们就能够很好的区分出训练集和测试集。

图2 分类器通过「年龄」可以轻松区分训练集和测试集

具体步骤:

  1. 定义y:样本是train还是test。
  2. 将 Train 和 Test 合成一个数据集
  3. 构造一个模型,拟合新定义的y
  4. 观察模型效果:如果模型的AUC超过0.7,说明了 Train 和 Test 的分布存在较大的差异
# 定义新的Y
df_train['Is_Test'] = 0
df_test['Is_Test'] = 1# 将 Train 和 Test 合成一个数据集。
df_adv = pd.concat([df_train, df_test])

4 分布变化时,有哪些优于交叉验证的方法?

4.1 人工划分验证集

人工划分验证集,需要我们对数据有充分的了解。

因为这次比赛的数据是根据时间划分的,所以我的验证集同样可以根据时间划分。

如果我们不清楚训练集和测试集如何划分,可以采用后面两种方法。

# 将样本根据时间排序
df_train = df_train.sort_values('Date').reset_index(drop=True)
df_train.drop(['Date'], axis=1, inplace=True)# 前80%的样本作为训练集,后20%的样本作为验证集
df_validation_1 = df_train.iloc[int(0.8 * len(df_train)):, ]
df_train_1 = df_train.iloc[:int(0.8 * len(df_train)), ]

4.2 和测试集最相似的样本作为验证集

如果对数据没有充分了解,如何找到训练集中,和测试集分布最相似的样本呢?

这就会用到我们做对抗验证时,模型预测样本是测试集的概率。概率越高,则说明和测试集越相似。

# 通过抗验证中的模型,得到各个样本属于测试集的概率
model_adv.fit(df_adv.drop('Is_Test', axis=1), df_adv.loc[:, 'Is_Test'])
preds_adv = model_adv.predict_proba(df_adv.drop('Is_Test', axis=1))[:, 1]# 只需要训练样本的概率
df_train_copy = df_train.copy()
df_train_copy['is_test_prob'] = preds_adv[:len(df_train)]# 根据概率排序
df_train_copy = df_train_copy.sort_values('is_test_prob').reset_index(drop=True)# 将概率最大的20%作为验证集
df_validation_2 = df_train_copy.iloc[int(0.8 * len(df_train)):, ]
df_train_2 = df_train_copy.iloc[:int(0.8 * len(df_train)), ]

4.3 有权重的交叉验证

不仅可以用对抗验证中,样本是测试集的概率来划分验证集,也可以将这个概率作为样本的权重。

概率越高,和测试集就越相似,权重就越高。这样,我们就可以做有权重的交叉验证。

# 生成lightgbm的数据格式,赋予各个样本权重
train_set = lgb.Dataset(df_train.drop('HasDetections', axis=1),label=df_train.loc[:, 'HasDetections'], weight=preds_adv[:len(df_train)])

5 实例

5.1 用到的数据

图3 微软恶意软件比赛

这里用到的数据来自Kaggle上的微软恶意软件比赛。

因为这次比赛的 Train 和 Test 是根据时间划分的,所以Train 和 Test 的分布非常不同,很具有代表性。

通过对该数据做对抗验证,我们发现模型的AUC达到了0.99。说明本次比赛的训练集和测试集的样本分布存在较大的差异。

5.2 对比各种方法的效果

分别使用上述提到的总共4种方法,我们来对比一下四种方法的效果,如下表:

图4 比较各类方法训练集和测试集AUC

使用交叉验证时,验证集AUC和测试集AUC的差值是最大的,远高于其他方式。说明在样本分布发生变化时,交叉验证不能够准确评估模型在测试集上的效果。

5.3 为什么评价方式是差值,而不是测试集AUC?

有人可能会提到,哪种方法在测试集上的AUC最高,哪种方法就更好,不是吗?

需要注意的是,本文讨论的不是“提升”模型效果的方法,而是“评估”模型效果的方法。

具体来说,虽然目前看来,比如交叉验证在测试集上的AUC,略高于有权重的交叉验证。

但是,当前的模型只是一个很基础的模型(Baseline Model),没有做任何的变量筛选,特征工程,以及模型调参。

由于所有的优化模型的决定,都将基于验证集,而交叉验证无法准确评估模型在测试集上的效果,这将导致很多优化模型的决定是错误的。

只有在有一个可靠的验证集的情况下,提升模型在验证集上效果的方法,我们才有信心认为,它也可以提升在测试集上的表现。

另外,从本次比赛的结果,我们也可以发现,最终排名很好的参赛者,都没有使用交叉验证。

6 结论

在样本分布发生变化时,交叉验证不能够准确评估模型在测试集上的效果。

这里建议采用其他方式:

  • 人工划分验证集
  • 和测试集最相似的样本作为验证集
  • 有权重的交叉验证

训练集和测试集样本分布一致性的判断方法相关推荐

  1. fgvc-aircraft-2013b飞机细粒度数据训练集和测试集划分python代码

    fgvc-aircraft-2013b是细粒度图像分类和识别研究中经典的benchmarks,它包含四种类型的标注: (1)按照manufacturer进行划分,可分为30个类别,例如ATR.Airb ...

  2. 将数据集分为训练集和测试集(python脚本)

    文章目录 程序: 下面简单介绍一下程序流程 1.引入库 os库 shutil random 2.mk_file函数 3.主函数 程序: 我们在训练卷积神经网络之前,要搭建好数据集,分成训练集和测试集两 ...

  3. sklearn.model_selection.train_test_split随机划分训练集和测试集

    1 函数用途 train_test_split()是交叉验证中常用的函数,功能是将数组或矩阵按比例随机划分为训练集和测试集,使用方法为: X_train,X_test, y_train, y_test ...

  4. python尝试不同的随机数进行数据划分、使用卡方检验依次计算不同随机数划分下训练接和测试集所有分类特征的卡方检验的p值,如果所有p值都大于0.05则训练集和测试集都具有统计显著性、数据划分合理

    python尝试不同的随机数进行数据划分.使用卡方检验依次计算不同随机数划分下训练接和测试集所有分类特征(categorical)的卡方检验的p值,如果所有p值都大于0.05则退出循环.则训练集和测试 ...

  5. R语言使用lm构建线性回归模型、并将目标变量对数化实战:模型训练集和测试集的残差总结信息(residiual summary)、模型训练(测试)集自由度计算、模型训练(测试)集残差标准误计算

    R语言使用lm构建线性回归模型.并将目标变量对数化实战:模型训练集和测试集的残差总结信息(residiual summary).模型训练(测试)集自由度计算.模型训练(测试)集残差标准误计算(Resi ...

  6. R语言决策树、bagging、随机森林模型在训练集以及测试集的预测结果(accuray、F1、偏差Deviance)对比分析、计算训练集和测试集的预测结果的差值来分析模型的过拟合(overfit)情况

    R语言决策树.bagging.随机森林模型在训练集以及测试集的预测结果(accuray.F1.偏差Deviance)对比分析.计算训练集和测试集的预测结果的差值来分析模型的过拟合(overfit)情况 ...

  7. 解决TensorBoard训练集和测试集指标只能分开显示的问题(基于Keras)

    解决TensorBoard训练集和测试集指标只能分开显示的问题(基于Keras) 参考文章: (1)解决TensorBoard训练集和测试集指标只能分开显示的问题(基于Keras) (2)https: ...

  8. Sklearn-train_test_split随机划分训练集和测试集

    sklearn.model_selection.train_test_split随机划分训练集和测试集 官网文档:http://scikit-learn.org/stable/modules/gene ...

  9. python划分数据集用pandas_用pandas划分数据集实现训练集和测试集

    1.使用model_select子模块中的train_test_split函数进行划分 数据:使用kaggle上Titanic数据集 划分方法:随机划分 # 导入pandas模块,sklearn中mo ...

  10. 31,32,33_过拟合、欠拟合的概念、L2正则化,Pytorch过拟合欠拟合,交叉验证-Train-Val-Test划分,划分训练集和测试集,K-fold,Regularization

    1.26.过拟合.欠拟合及其解决方案 1.26.1.过拟合.欠拟合的概念 1.26.1.1.训练误差和泛化误差 1.26.1.2.验证数据集与K-fold验证 1.26.1.3.过拟合和欠拟合 1.2 ...

最新文章

  1. flex图表数据动态更新效果示例
  2. 项目服务器有15个能说明什么,15.1 我的面试经历 by smyhvae - 前端入门进阶
  3. 周末都花费在智能车实验室,结果......
  4. 【python进阶】_多线程多进程
  5. 4 在vCenter Server安装View Composer组件
  6. Delphi XE2 - 点点滴滴设置
  7. cloc工具 linux,Linux下源代码行数统计工具(sloccount,cloc等)
  8. [Publish AAR To Maven] 使用 Gradle 发布 AAR 到 Maven 仓库
  9. Gmail使用POP3设置的奥秘
  10. Hive报错Error during job, obtaining debugging information...
  11. 从KMP到FSA有限状态自动机字符串匹配
  12. 几种spootboot配置参数线上修改方法
  13. Redis 如何实现库存扣减操作和防止被超卖
  14. 根据公开信息 已有15家公司参与央行数字货币
  15. C++中类(class)和结构(struct)的区别
  16. 解决error: unknown type name ‘__u8’问题,认识__u8,__u16,__u32,__u64的大小及作用
  17. webgl_浏览器支持问题
  18. 100天精通Python(数据分析篇)——第66天:Pandas透视表基础+实战案例(pivot_table函数)
  19. 自动驾驶 - 滤波算法
  20. JERK、Junction Deviation、Linear Advance

热门文章

  1. 联想软件商店安装教程
  2. 东芝移动硬盘拆解图_拆解报告:小米USB 3.0分线器XMFXQ01QM
  3. 详解全局免流原理(转载)
  4. 微信小程序-wxParse插件的使用
  5. 大数据项目实训教学解决方案
  6. Android项目中的armeabi,armeabi-v7a和x86
  7. AltRun调用cmd并刷新DNS
  8. ARM指令集与Thumb指令集与Thumb-2指令集的区别
  9. 机器学习实验——回归预测算法
  10. wbe下载Excel文件Response响应头格式