訓(xùn)練/測(cè)試集分布不一致解法總結(jié)
訓(xùn)練集高分,測(cè)試集預(yù)測(cè)提交后發(fā)現(xiàn)分?jǐn)?shù)很低,為什么?有可能是訓(xùn)練集和測(cè)試集分布不一致,導(dǎo)致模型過擬合訓(xùn)練集,個(gè)人很不喜歡碰到這種線下不錯(cuò)但線上抖動(dòng)過大的比賽,有種讓你感覺好像在“碰運(yùn)氣”,看誰(shuí)“碰”對(duì)了測(cè)試集的分布。但實(shí)際是有方法可循的,而不是說(shuō)純碰運(yùn)氣。本文我將從“訓(xùn)練/測(cè)試集分布不一致問題”的發(fā)生原因講起,然后羅列判斷該問題的方法和可能的解決手段。

一、發(fā)生原因
訓(xùn)練集和測(cè)試集分布不一致也被稱作數(shù)據(jù)集偏移(Dataset Shift)。西班牙格拉納達(dá)大學(xué)Francisco Herrera教授在他PPT [1] 里提到數(shù)據(jù)集偏移有三種類型:
-
協(xié)變量偏移(Covariate Shift) : 獨(dú)立變量的偏移,指訓(xùn)練集和測(cè)試集的輸入服從不同分布,但背后是服從同一個(gè)函數(shù)關(guān)系,如圖1所示。
-
先驗(yàn)概率偏移(Prior Probability Shift) : 目標(biāo)變量的偏移。
-
概念偏移(Concept Shift) : 獨(dú)立變量和目標(biāo)變量之間關(guān)系的偏移。

圖1:協(xié)變量偏移
最常見的有兩種原因 [1] :
-
樣本選擇偏差(Sample Selection Bias) : 訓(xùn)練集是通過有偏方法得到的,例如非均勻選擇(Non-uniform Selection),導(dǎo)致訓(xùn)練集無(wú)法很好表征的真實(shí)樣本空間。
-
環(huán)境不平穩(wěn)(Non-stationary Environments) : 當(dāng)訓(xùn)練集數(shù)據(jù)的采集環(huán)境跟測(cè)試集不一致時(shí)會(huì)出現(xiàn)該問題,一般是由于時(shí)間或空間的改變引起的。
在分類任務(wù)上,有時(shí)候官方隨機(jī)劃分?jǐn)?shù)據(jù)集,沒有考慮類別平衡問題,例如: 訓(xùn)練集類別A數(shù)據(jù)量遠(yuǎn)多于類別B,而測(cè)試集相反,這類樣本選擇偏差問題會(huì)導(dǎo)致訓(xùn)練好的模型在測(cè)試集上魯棒性很差,因?yàn)橛?xùn)練集沒有很好覆蓋整個(gè)樣本空間。此外,除了目標(biāo)變量,輸入特征也可能出現(xiàn)樣本選擇偏差問題,比如要預(yù)測(cè)泰坦尼克號(hào)乘客存活率,而訓(xùn)練集輸入特征里“性別”下更多是男性,而測(cè)試集里“性別”更多是女性,這樣也會(huì)導(dǎo)致模型在測(cè)試集上表現(xiàn)差。
樣本選擇偏差也有些特殊的例子,之前我參加阿里天池2021“AI Earth”人工智能創(chuàng)新挑戰(zhàn)賽 [2] ,官方提供兩類數(shù)據(jù)集作為訓(xùn)練集,分別是CMIP模擬數(shù)據(jù)和SODA真實(shí)數(shù)據(jù),然后測(cè)試集又是SODA真實(shí)數(shù)據(jù),CMIP模擬數(shù)據(jù)是通過系列氣象模型仿真模擬得到的,即有偏方法,但選手都會(huì)選擇將模擬數(shù)據(jù)加入訓(xùn)練,因?yàn)橛?xùn)練集真實(shí)數(shù)據(jù)太少了,可模擬數(shù)據(jù)的加入也無(wú)可避免的引入了樣本選擇偏差。
聊完樣本選擇偏移,我們聊下環(huán)境不平穩(wěn)帶來(lái)的數(shù)據(jù)偏移,我想最常見是在時(shí)序比賽里了吧,用歷史時(shí)序數(shù)據(jù)預(yù)測(cè)未來(lái)時(shí)序,未來(lái)突發(fā)事件很可能帶來(lái)時(shí)序的不穩(wěn)定表現(xiàn),這便帶來(lái)了分布差異。環(huán)境因素不僅限于時(shí)間和空間,還有數(shù)據(jù)采集設(shè)備、標(biāo)注人員等。
二、判斷方法

1.?KDE (核密度估計(jì))分布圖
當(dāng)我們一想到要對(duì)比訓(xùn)練集和測(cè)試集的分布,便是畫概率密度函數(shù)直方圖,但直方圖看分布有兩點(diǎn)缺陷: 受bin寬度影響大和不平滑,因此多數(shù)人會(huì)偏向于使用核密度估計(jì)圖(Kernel Density Estimation, KDE),KDE是非參數(shù)檢驗(yàn),用于估計(jì)分布未知的密度函數(shù),相比于直方圖,它受bin影響更小,繪圖呈現(xiàn)更平滑,易于對(duì)比數(shù)據(jù)分布。我研究生的有一門課的小作業(yè)有要去對(duì)比直方圖和KDE圖,相信這個(gè)能幫助大家更直觀了解到它們的差異:

圖2:心臟疾病患者最大心率的概率密度函數(shù)分布圖,數(shù)據(jù)源自UCI ML開放數(shù)據(jù)集
這里在略微細(xì)講下KDE,我們先看KDE函數(shù):
??是來(lái)自未知分布的樣本,??是樣本總數(shù),??是核函數(shù),h是帶寬(Bandwidth)。 核函數(shù)定義一個(gè)用于生成PDF(概率分布函數(shù)Probability Distribution Function)的曲線,不同于將值放入離散bins內(nèi),核函數(shù)對(duì)每個(gè)樣本值都創(chuàng)建一個(gè)獨(dú)立的概率密度曲線,然后加總這些平滑曲線,最終得到一個(gè)平滑連續(xù)的概率分布曲線,如下圖所示:

圖3:生成KDE的過程呈現(xiàn)[3]
言歸正傳,對(duì)比訓(xùn)練集和測(cè)試集特征分布時(shí),我們可以用seaborn.kdeplot() [4] 進(jìn)行繪圖可視化,樣例圖和代碼如下:

圖4:不同數(shù)據(jù)集下的KDE對(duì)比
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# 創(chuàng)建樣例特征
train_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).T
# 繪KDE對(duì)比分布
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()
2.KS檢驗(yàn)
KDE是PDF來(lái)對(duì)比,而KS檢驗(yàn)是基于CDF(累計(jì)分布函數(shù)Cumulative Distribution Function)來(lái)檢驗(yàn)兩個(gè)數(shù)據(jù)分布是否一致,它也是非參數(shù)檢驗(yàn)方法(即不知道數(shù)據(jù)分布情況)。兩條不同數(shù)據(jù)集下的CDF曲線,它們最大垂直差值可用作描述分布差異(見下圖5中的D)。

圖5:不同數(shù)據(jù)集下的CDF對(duì)比[5]
調(diào)用scipy.stats.ks_2samp() [6] 可輕松得到KS的統(tǒng)計(jì)值(最大垂直差)和假設(shè)檢驗(yàn)下的p值:
from scipy import stats
stats.ks_2samp(train_feat, test_feat)
輸出:KstestResult(statistic=0.2, pvalue=0.2719135601522248)
若KS統(tǒng)計(jì)值小且p值大,則我們可以接受KS檢驗(yàn)的原假設(shè)H0,即兩個(gè)數(shù)據(jù)分布一致。上面樣例數(shù)據(jù)的統(tǒng)計(jì)值較低,p值大于10%但不是很高,因此反映分布略微不一致。注意: p值<0.01,強(qiáng)烈建議拒絕原假設(shè)H0,p值越大,越傾向于原假設(shè)H0成立。
3.?對(duì)抗驗(yàn)證
對(duì)抗驗(yàn)證是個(gè)很有趣的方法,它的思路是:我們構(gòu)建一個(gè)分類器去分類訓(xùn)練集和測(cè)試集,如果模型能清楚分類,說(shuō)明訓(xùn)練集和測(cè)試集存在明顯區(qū)別(即分布不一致),否則反之。具體步驟如下:
-
訓(xùn)練集和測(cè)試集合并,同時(shí)新增標(biāo)簽‘Is_Test’去標(biāo)記訓(xùn)練集樣本為0,測(cè)試集樣本為1。
-
構(gòu)建分類器(例如LGB, XGB等)去訓(xùn)練混合后的數(shù)據(jù)集(可采用交叉驗(yàn)證的方式),擬合目標(biāo)標(biāo)簽‘Is_Test’。
-
輸出交叉驗(yàn)證中最優(yōu)的AUC分?jǐn)?shù)。AUC越大(越接近1),越說(shuō)明訓(xùn)練集和測(cè)試集分布不一致。
相關(guān)代碼可參考Qiuyan918在Kaggle的Microsoft Malware Prediction比賽中使用實(shí)例代碼 [7] 。

圖6:對(duì)抗驗(yàn)證示意圖
三、解決方法

1.?構(gòu)造合適的驗(yàn)證集
當(dāng)出現(xiàn)訓(xùn)練集和測(cè)試集分布不一致的,我們可以試圖去構(gòu)建跟測(cè)試集分布近似相同的驗(yàn)證集,保證線下驗(yàn)證跟線上測(cè)試分?jǐn)?shù)不會(huì)抖動(dòng),這樣我們就能得到穩(wěn)定的benchmark。Qiuyan918在基于對(duì)抗驗(yàn)證的基礎(chǔ)上,提出了三種構(gòu)造合適的驗(yàn)證集的辦法:
-
人工劃分驗(yàn)證集
-
選擇和測(cè)試集最相似的樣本作為驗(yàn)證集
-
有權(quán)重的交叉驗(yàn)證
接下來(lái),我將依次細(xì)講上述方法。
(1)?人工劃分驗(yàn)證集
以時(shí)間序列舉例,因?yàn)橐话銣y(cè)試集也會(huì)是未來(lái)數(shù)據(jù),所以我們也要保證訓(xùn)練集是歷史數(shù)據(jù),而劃分出的驗(yàn)證集是未來(lái)數(shù)據(jù),不然會(huì)發(fā)生“時(shí)間穿越”的數(shù)據(jù)泄露問題,導(dǎo)致模型過擬合(例如用未來(lái)預(yù)測(cè)歷史數(shù)據(jù)),這個(gè)時(shí)候就有兩種驗(yàn)證劃分方式可參考使用:
-
TimeSeriesSplit :Sklearn提供的TimeSeriesSplit。
-
固定窗口滑動(dòng)劃分法 :固定時(shí)間窗口,不斷在數(shù)據(jù)集上滑動(dòng),獲得訓(xùn)練集和驗(yàn)證集。(個(gè)人推薦這種)

圖7:劃分時(shí)序數(shù)據(jù)的兩種方法
除了時(shí)間序列數(shù)據(jù),其它數(shù)據(jù)集的驗(yàn)證集劃分都要遵循一個(gè)原則,即盡可能符合測(cè)試集的數(shù)據(jù)模式。像前面提到的2021“AI Earth”人工智能創(chuàng)新挑戰(zhàn)賽中氣象數(shù)據(jù),由于測(cè)試集是真實(shí)氣象數(shù)據(jù),那么我們劃分驗(yàn)證集時(shí),更傾向于使用真實(shí)氣象數(shù)據(jù)去評(píng)估線下模型的表現(xiàn),而不是使用模擬氣象數(shù)據(jù)作為驗(yàn)證集。
(2)?選擇和測(cè)試集最相似的樣本作為驗(yàn)證集
前面在講對(duì)抗驗(yàn)證時(shí),我們有訓(xùn)練出一個(gè)分類器去分類訓(xùn)練集和測(cè)試集,那么自然我們也能預(yù)測(cè)出訓(xùn)練集屬于測(cè)試集的概率(即訓(xùn)練集在‘Is_Test’標(biāo)簽下預(yù)測(cè)概率),我們對(duì)訓(xùn)練集的預(yù)測(cè)概率進(jìn)行降序排列,選擇概率最大的前20%樣本劃分作為驗(yàn)證集,這樣我們就能從原始數(shù)據(jù)集中,得到分布跟測(cè)試集接近的一個(gè)驗(yàn)證集了,具體樣例代碼詳見 [7] 。之后,我們還可以評(píng)估劃分好的驗(yàn)證集跟測(cè)試集的分布狀況,評(píng)估方法:將驗(yàn)證集和測(cè)試集做對(duì)抗驗(yàn)證,若AUC越小,說(shuō)明劃分出的驗(yàn)證集和測(cè)試集分布越接近(即分類器越分不清驗(yàn)證集和測(cè)試集)。

圖8:選擇和測(cè)試集最相似的樣本作為驗(yàn)證集
(3)?有權(quán)重的交叉驗(yàn)證
如果我們對(duì)訓(xùn)練集里分布更偏向于測(cè)試集分布的樣本更大的樣本權(quán)重,給與測(cè)試集分布不太一致的訓(xùn)練集樣本更小權(quán)重,也能一定程度上,幫助我們線下得到不易抖動(dòng)的評(píng)估分?jǐn)?shù)。在lightgbm庫(kù)的Dataset初始化參數(shù)中,便提供了樣本加權(quán)的參數(shù)weight,詳見文檔 [8] 。圖7中,對(duì)抗驗(yàn)證的分類器預(yù)測(cè)訓(xùn)練集的Is_Test概率作為權(quán)重即可。
2.?刪除分布不一致特征
如果我們遇到分布不一致且不太重要的特征,我們可以選擇直接刪去這種特征。該方法在各大比賽中十分常見。例如: 在2018年螞蟻金服風(fēng)險(xiǎn)大腦-支付風(fēng)險(xiǎn)識(shí)別比賽中,亞軍團(tuán)隊(duì)根據(jù)特征在訓(xùn)練集和測(cè)試集上的表現(xiàn),去除分布差異較大的特征,如圖9 [9] 。

圖9:螞蟻金服支付風(fēng)險(xiǎn)識(shí)別比賽中刪除分布不一致特征[9]
雖然個(gè)人建議的是刪除分布不一致但不太重要的特征,但有時(shí)避免不了碰到分布不一致但又很重要的特征,這時(shí)候其實(shí)就需要自行trade off特征分布和特征重要性的關(guān)系了,比如在第四屆工業(yè)大數(shù)據(jù)創(chuàng)新競(jìng)賽-注塑成型工藝的虛擬量測(cè)中,第5名團(tuán)隊(duì)保留了sensor1_mean特征而刪除了pack_press_2特征,盡管他們發(fā)現(xiàn)pack_press_2從實(shí)際生產(chǎn)角度和相關(guān)性角度都非常重要,可為了提升模型在測(cè)試集的泛化能力和分?jǐn)?shù),他們沒用pack_press_2特征,如圖10 [10] 。

圖10:注塑成型工藝的虛擬量測(cè)比賽中刪除分布不一致特征[10]
3.?修正分布不一致的特征輸入
當(dāng)我們對(duì)比觀察訓(xùn)練集和測(cè)試集的KDE時(shí),若發(fā)現(xiàn)對(duì)數(shù)據(jù)做數(shù)學(xué)運(yùn)算(例如加減乘除)或?qū)?strong>增刪樣本就能修正分布,使得分布接近一致,那么我們可以試試。比如,螞蟻金服比賽里,亞軍團(tuán)隊(duì)發(fā)現(xiàn)"用戶交易請(qǐng)求"特征在訓(xùn)練集中包含0、1和-1,而測(cè)試集只有1和0樣本,因此他們對(duì)訓(xùn)練集刪去了特征值為-1的樣本,減少該特征在訓(xùn)練集和測(cè)試集的差異 [9] 。
4. 修正分布不一致的預(yù)測(cè)輸出
除了對(duì)輸入特征進(jìn)行分布檢查,我們也可以檢查目標(biāo)特征的分布,看是否存在可修正的空間。這種案例很少見,因?yàn)檎G闆r下,你看不到測(cè)試集的目標(biāo)特征值。在“AI Earth”人工智能創(chuàng)新挑戰(zhàn)賽里,我們有提到官方提供兩類數(shù)據(jù)集作為訓(xùn)練集,分別是CMIP模擬數(shù)據(jù)和SODA真實(shí)數(shù)據(jù),然后測(cè)試集又是SODA真實(shí)數(shù)據(jù),其中前排參賽者YueTan就將CMIP和SODA的目標(biāo)特征分布畫在一起,然后發(fā)現(xiàn)SODA的值更集中,且整體分布偏右一些,所以對(duì)用CMIP訓(xùn)練得到的預(yù)測(cè)值加了一個(gè)小的常數(shù),修正CMIP下模型的預(yù)測(cè)輸出,使得它分布更偏向于SODA分布 [11] 。

圖11:氣象數(shù)據(jù)SODA真實(shí)值和CMIP模擬值分布對(duì)比[11]
5. 偽標(biāo)簽
偽標(biāo)簽是半監(jiān)督方法,利用未標(biāo)注數(shù)據(jù)加入訓(xùn)練,我們先看看偽標(biāo)簽的思路,再討論為什么它可能在一定程度上對(duì)分布不一致的數(shù)據(jù)集有幫助。偽標(biāo)簽最常見的方法是:
-
使用有標(biāo)注的訓(xùn)練集訓(xùn)練模型M;
-
然后用模型M預(yù)測(cè)未標(biāo)注的測(cè)試集;
-
選取測(cè)試集中預(yù)測(cè)置信度高的樣本加入訓(xùn)練集中;
-
使用標(biāo)注樣本和高置信度的預(yù)測(cè)樣本訓(xùn)練模型M';
-
預(yù)測(cè)測(cè)試集,輸出預(yù)測(cè)結(jié)果。
TripleLift知乎主提供的入門版?zhèn)螛?biāo)簽思路圖如下所示,建議有興趣的朋友閱讀他原文 [12] ,他還提供了進(jìn)階版和創(chuàng)新版的偽標(biāo)簽技術(shù),值得借鑒學(xué)習(xí)。

圖12:入門版?zhèn)螛?biāo)簽思路圖
由上圖我們可以看到,模型的訓(xùn)練引入了部分測(cè)試集的樣本,這樣相當(dāng)于引入了部分測(cè)試集的分布。但需要注意:
(1) 相比于前面的方法,偽標(biāo)簽通常沒有表現(xiàn)的很好,因?yàn)樗氲氖侵眯哦雀叩臏y(cè)試集樣本,這些樣本很可能跟訓(xùn)練集分布接近一致,所以才會(huì)預(yù)測(cè)概率高。因此引入的測(cè)試集分布也沒有很不同,所以使用時(shí)常發(fā)生過擬合的情況。
(2) 注意引入的是高置信度樣本,如果引入低置信度樣本,會(huì)帶來(lái)很大的噪聲。另外,高置信度樣本也不建議選取過多加入訓(xùn)練集,這也是為了避免模型過擬合。
(3) 偽標(biāo)簽適用于圖像領(lǐng)域更多些,表格型比賽建議最后沒辦法再考慮該方法,因?yàn)楸救耸褂眠^該方法,漲分的可能性都不是很高(也可能是我沒用好)。
6. 其它
在寫文章的時(shí)候,我查知乎發(fā)現(xiàn)有個(gè)問答《訓(xùn)練集和測(cè)試集的分布差距太大有好的處理方法嗎?》下,知乎主納米醬提到:"特征數(shù)值差距不大,特征相關(guān)性差距也不大,但是目標(biāo)數(shù)值差距過大,這個(gè)好辦,改變?nèi)蝿?wù)設(shè)置共同的中間目標(biāo),比如你說(shuō)的目標(biāo)值是否可以采取相對(duì)值,增長(zhǎng)率,夏普等,而非絕對(duì)值"[13]。這種更改預(yù)測(cè)目標(biāo)的方法,可能是發(fā)現(xiàn)更改預(yù)測(cè)目標(biāo)后,新的預(yù)測(cè)目標(biāo)值分布會(huì)變得相對(duì)一致,所以才考慮該方法的。但實(shí)際中,我沒碰過這種情境,但還是提出來(lái)讓大家參考學(xué)習(xí)下。
四、總結(jié)
通過這次整理,我對(duì)“訓(xùn)練集和測(cè)試集分布不一致”問題有了一個(gè)大致的知識(shí)框架,也學(xué)到了不少,特別是對(duì)抗驗(yàn)證這塊,希望大家也有所獲,歡迎交流討論。
參考資料
[1]?? Dataset Shift in Classification: Approaches and Problems - Francisco Herrera, PPT: http://iwann.ugr.es/2011/pdf/InvitedTalk-FHerrera-IWANN11.pdf
[2] 2021“AI Earth”人工智能創(chuàng)新挑戰(zhàn)賽 - 阿里天池, 比賽: https://tianchi.aliyun.com/competition/entrance/531871/introduction
[3] Kernel Distribution - MathWorks, 文檔: https://www.mathworks.com/help/stats/kernel-distribution.html
[4] seaborn.kdeplot(), 文檔: http://seaborn.pydata.org/generated/seaborn.kdeplot.html
[5] KS-檢驗(yàn)(Kolmogorov-Smirnov test)-- 檢驗(yàn)數(shù)據(jù)是否符合某種分布 - Arkenstone, 博客: https://www.cnblogs.com/arkenstone/p/5496761.html
[6] scipy.stats.ks_2samp(), 文檔: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.ks_2samp.html
[7] Adversarial_Validation - Qiuyuan918, 代碼: https://github.com/Qiuyan918/Adversarial_Validation_Case_Study/blob/master/Adversarial_Validation.ipynb
[8] lightgbm.Dataset(), 文檔: https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.Dataset.html#lightgbm.Dataset
[9] 螞蟻金服ATEC風(fēng)險(xiǎn)大腦-支付風(fēng)險(xiǎn)識(shí)別--TOP2方案 - 吊車尾學(xué)院-E哥, 文章: https://zhuanlan.zhihu.com/p/57347243?from_voters_page=true
[10] 工業(yè)大數(shù)據(jù)之注塑成型虛擬量測(cè)Top5分享 - 公眾號(hào): Coggle數(shù)據(jù)科學(xué)
[11] 數(shù)據(jù)敏感度:以AI earth為栗子 - 公眾號(hào): YueTan
[12] 偽標(biāo)簽(Pseudo-Labelling)——鋒利的匕首 - TripleLift, 文章: https://zhuanlan.zhihu.com/p/157325083
[13] 訓(xùn)練集和測(cè)試集的分布差距太大有好的處理方法嗎?- 知乎, 文章: https://www.zhihu.com/question/265829982/answer/1770310534
干貨學(xué)習(xí), 點(diǎn) 贊 三連 ↓
