训练集与测试集数据分布不一致
簡介
數據質量的高低是決定使用機器學習算法獲得預測結果質量高低的重要因素,在很多常見任務中,數據質量的作用遠大于模型的作用,本文討論數據預處理時會遇到的一個常見問題:訓練集與測試集數據分布不一致。
什么是訓練集與測試集數據分布不一致?
一個具體的例子,比如我現在要預測泰坦尼克號乘客存活率(Kaggle 上的經典題,已經被各路選手將準確率刷爆了),如果訓練集的輸入特征中,“性別” 這一特征多數是男性,而在測試集里,“性別” 這一特征多數是女性,這便是訓練集與測試集上,某特征其數據分布不均。
訓練集和測試集分布不一致也被稱作數據集偏移 (Dataset Shift),導致這種問題有兩個常見原因:
樣本選擇偏差 (Sample Selection Bias): 訓練集是通過有偏方法得到的,例如非均勻選擇 (Non-uniform Selection),導致訓練集無法很好表征的真實樣本空間。
環境不平穩 (Non-stationary Environments): 當訓練集數據的采集環境跟測試集不一致時會出現該問題,一般是由于時間或空間的改變引起的。
先討論樣本選擇偏差,在有監督學習里,樣本會分為特征數據 (feature) 與目標變量 (label),樣本選擇偏差也會分分為兩種情況:
沒有考慮數據中不同特征的分布問題,如前面舉例的預測泰坦尼克號乘客存活率問題,訓練集的性別特征中,男性比例大,而測試集的性別特征中,女性比例大。
沒有考慮數據中目標變量分布問題,從而會出現:訓練集類別 A 數據量遠多于類別 B,而測試集相反的情況。
樣本選擇偏差會導致訓練好的模型在測試集上魯棒性很差,因為訓練集沒有很好覆蓋整個樣本空間。
接著討論環境不平穩帶來的數據偏移,最典型的就是在時序數據中,用歷史時序數據預測未來時序,未來突發事件很可能帶來時序的不穩定表現,這便帶來了分布差異。
環境因素不僅限于時間和空間,還有數據采集設備、標注人員等。
校驗數據分布
如何判斷訓練集與測試集數據分布是否不一致呢?
通常使用核密度估計 (kernel density estimation, KDE) 分布圖和 KS 校驗這兩種方法來判斷。
KDE 分布圖
在討論 KDE 分布圖之前,先考慮一下使用概率密度直方圖來判斷數據分布的問題。
概率密度直方圖是用數據集中不同數據出現的次數來表示其概率,需注意這種假設不一定成立。
要對比訓練集和測試集數據的分布,我們可以通過繪制相應的概率密度直方圖,然后直觀的判斷直方圖的差異,但通過直方圖判斷數據分布的會有兩個缺陷:
1. 受 bin 寬度影響大
2. 不平滑
而 KDE 分布圖相比于直方圖,它受 bin 影響更小,繪圖呈現更平滑,易于對比數據分布,下圖便是直方圖和核密度估計的一個對比:
在進一步討論 KDE 前,先討論一下核函數,核函數定義一個用于生成 PDF (概率分布函數,Probability Distribution Function) 的曲線,不同于將值放入離散 bins 中,核函數對每個樣本值都創建一個獨立的概率密度曲線,然后加和這些平滑曲線,最終得到一個平滑連續的概率分布曲線。
“核” 在不同的語境下的含義是不同的,在 “非參數估計”(即不知道數據分布情況) 的語境下,“核” 是一個函數,用來提供權重。例如高斯函數 (Gaussian) 就是一個常用的核函數。
KDE 在數學上還有挺多細節,但在實現上,通過 seaborn 庫便可以輕松實現,代碼如下:
import?numpy?as?np import?seaborn?as?sns import?matplotlib.pyplot?as?plt#?創建樣例特征 train_mean,?train_cov?=?[0,?2],?[(1,?.5),?(.5,?1)] test_mean,?test_cov?=?[0,?.5],?[(1,?1),?(.6,?1)] #??np.random.multivariate_normal?從多變量正態分布中隨機抽取樣本 #?多正態分布是一維正態分布向高維的推廣。這樣的分布是由它的平均值和協方差矩陣來確定的。 #?這些參數類似于一維正態分布的均值(平均或“中心”)和方差(標準差或“寬度”的平方)。 train_feat,?_?=?np.random.multivariate_normal(train_mean,?train_cov,?size=50).T test_feat,?_?=?np.random.multivariate_normal(test_mean,?test_cov,?size=50).T#?繪KDE對比分布 sns.kdeplot(train_feat,?shade?=?True,?color='r',?label?=?'train') sns.kdeplot(test_feat,?shade?=?True,?color='b',?label?=?'test') plt.xlabel('Feature') plt.legend() plt.show()注意,上述代碼中,train_feat 參數是一維的(即單獨某個特征的分布,多個多特征,需要繪制多個KDE分布圖)。效果如圖所示:
從上圖可知,訓練集與測試集分布差異不大,可以繼續模型訓練等操作,如果分布差異較大,比如下圖這種,就需要對原始數據進行處理了。
KS 檢驗
KDE 是使用 PDF 來對比,而 KS 檢驗是基于 CDF (累計分布函數 Cumulative Distribution Function) 來檢驗兩個數據分布是否一致,它也是非參數檢驗方法。
KS 檢驗是基于累計分布函數,用于檢驗一個分布是否符合某種理論分布或比較兩個經驗分布是否有顯著差異。
KS 檢驗一般返回兩個值:
第一個值表示兩個分布之間的最大距離,值越小即這兩個分布的差距越小,分布也就越一致。
第二個值是 p 值,用來判定假設檢驗結果的一個參數,p 值越大,越不能拒絕原假設(待檢驗的兩個分布是同分布),即兩個分布越是同分布。
通過 scipy 庫可以快速實現 KS 檢驗,代碼如下:
from?traceback?import?print_tb import?numpy?as?np from?scipy?import?statstrain_mean,?train_cov?=?[0,?2],?[(1,?.5),?(.5,?1)] test_mean,?test_cov?=?[0,?.5],?[(1,?1),?(.6,?1)]train_feat,?_?=?np.random.multivariate_normal(train_mean,?train_cov,?size=50).T test_feat,?_?=?np.random.multivariate_normal(test_mean,?test_cov,?size=50).Tresult?=?stats.ks_2samp(train_feat,?test_feat) print(result)#?打印結果: #?KstestResult(statistic=0.18,?pvalue=0.3959398631708505)若 KS 統計值小且 p 值大,則可以接受 KS 檢驗的原假設,即兩個數據分布一致。
上面樣例數據的統計值較低,p 值大于 10% 但不是很高,因此反映分布略微不一致。如果p 值 < 0.01,建議拒絕原假設,p 值越大,越傾向于原假設成立。
分類器對抗驗證
所謂對抗驗證,就是構建一個分類模型去分類訓練集和測試集,如果分類模型可以清楚的分類,則說明訓練集和測試集的分布有明顯差異,反之分布差異不大。
分類模型可以直接使用 sklearn 中提供了幾種常見分類器來實現,比如 SVM。
具體步驟如下:
訓練集和測試集合并,同時新增標簽Is_Test去標記訓練集樣本為 0,測試集樣本為 1。
構建分類器 (例如?SVM、LGB、XGB 等) 去訓練混合后的數據集 (可采用交叉驗證的方式),擬合目標標簽Is_Test。
輸出交叉驗證中最優的 AUC 分數。AUC 越大 (越接近 1),越說明訓練集和測試集分布不一致。
結尾
本文的方法雖然基于訓練數據與測試數據進行討論,但同樣可以用于訓練數據與預測數據的分布檢測上,在模型訓練測試階段,我們會將已有的數據劃分為訓練數據與測試數據,當模型通過測試后,通常會合并訓練數據與測試數據,用所有數據進行訓練,獲得最終的模型,然后上線使用。
如果上線后效果不好,數據分布問題依舊要考慮,通常,我們會收集線上的待預測數據,將待預測數據的特征分與訓練數據的特征分布進行比較,依舊使用本文提及的方法,如果分布差異大,則說明,訓練數據無法代表待預測數據,當前模型是沒有實用價值的。
數據預處理是多數機器學習任務的核心,反倒是模型,因為很多成熟的實現,反而不是啥大問題。最近在整理自己過去的機器學習筆記,后續會將有價值的部分輸出到公眾號中。
本文相關參考:
訓練 / 測試集分布不一致解法總結
Python 可視化神器 Seaborn 入門系列 (一)——kdeplot 和 distplot?
密度估計(kernel density estimation)
總結
以上是生活随笔為你收集整理的训练集与测试集数据分布不一致的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 模块说明模板
- 下一篇: 1100个商务企业宣传通用PPT模板免费