工業界有一個大家公認的看法,“數據和特征決定了機器學習項目的上限,而算法只是盡可能地逼近這個上限”。在實戰中,特征工程幾乎需要一半以上的時間,是很重要的一個部分。缺失值處理、異常值處理、數據標准化、不平衡等問題大家應該都已經手到擒來小菜一碟了,本文我們探討一個很容易被忽視的坑:數據一致性。
眾所周知,大部分機器學習算法都有一個前提假設:訓練數據樣本和位置的測試樣本來自同一分布。如果測試數據的分布跟訓練數據不一致,那么就會影響模型的效果。
在一些機器學習相關的競賽中,給定的訓練集和測試集中的部分特征本身很有可能就存在分布不一致的問題。實際應用中,隨着業務的發展,訓練樣本分布也會發生變化,最終導致模型泛化能力不足。
下面就向大家介紹幾個檢查訓練集和測試集特征分布一致性的方法:
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 的樣本作為目標任務的驗證集,這樣即可將原始的樣本進行拆分得到訓練集,驗證集,測試集。
除了確定訓練集和測試集特征分布一致性,對抗驗證還可以用來做特征選擇。大家感興趣的話可以給個贊+在看,下一講《特征選擇》,我們用實例來看看對抗驗證的具體用法和效果。