請點擊此處輸入圖片描述 作者 | 吳曉暉 整理 | AI100(rgznai100) 原文 - https://zhuanlan.zhihu.com/p/27424282 不知道你有沒有這樣的感受,在剛剛入門機器學習的時候,我們一般都是從MNIST、CIFAR-10這一類知名公開數據集開始快速上手,復現別人的結果,但總覺得過于簡單,給人的感覺太不真實。因為這些數據太“完美”了(干凈的輸入,均衡的類別,分布基本一致的測試集,還有大量現成的參考模型),要成為真正的數據科學家,光在這些數據集上跑模型卻是遠遠不夠的。而現實中你幾乎不可能遇到這樣的數據(現實數據往往有著殘缺的輸入,類別嚴重不均衡,分布不一致甚至隨時變動的測試集,幾乎沒有可以參考的論文),這往往讓剛進入工作的同學手忙腳亂,無所適從。 Kaggle則提供了一個介于“完美”與真實之間的過渡,問題的定義基本良好,卻夾著或多或少的難點,一般沒有完全成熟的解決方案。在參賽過程中與論壇上的其他參賽者互動,能不斷地獲得啟發,受益良多。即使對于一些學有所成的高手乃至大牛,參加Kaggle也常常會獲得很多啟發,與來著世界各地的隊伍進行廝殺的刺激更讓人欲罷不能。更重要的是,Kaggle是業界普遍承認的競賽平臺,能從Kaggle上的一些高質量競賽獲取好名次,是對自己實力極好的證明,還能給自己的履歷添上光輝的一筆。如果能獲得金牌,殺入獎金池,那更是名利兼收,再好不過。 Kaggle適用于以下人群:
0 簡介 Kaggle創辦于2010年,目前已經被Google收購,是全球頂級的數據科學競賽平臺,在數據科學領域中享有盛名。筆者參加了由Quora舉辦的Quora Question Pairs比賽,并且獲得了前1%的成績(3307支隊伍)。這是筆者Kaggle首戰,所以寫下此文來系統化地梳理比賽的思路,并且和大家分享我們參賽的一些心得。 Quora Question Pairs是一個自然語言(NLP)比賽,比賽的題目可以簡單地概括為“預測兩個問句的語義相似的概率”。其中的樣本如下: 也許是作為Kaggle上為數不多的NLP比賽,這看似簡單的比賽卻吸引了眾多的參賽隊伍。由于這是NLP問題,所以接下來的介紹都會偏向于NLP,本文會分為以下三個部分:
1 比賽篇 為了方便,我們先定義幾個名詞:
1.1 分析題目 拿到賽題以后,第一步就是要破題,我們需要將問題轉化為相應的機器學習問題。其中,Kaggle最常見的機器學習問題類型有:
比如Quora的比賽就是二分類問題,因為只需要判斷兩個問句的語義是否相似。 1.2 數據分析(Data Exploration) 所謂數據挖掘,當然是要從數據中去挖掘我們想要的東西,我們需要通過人為地去分析數據,才可以發現數據中存在的問題和特征。我們需要在觀察數據的過程中思考以下幾個問題:
1.2.1 統計分析 對于數值類變量(Numerical Variable),我們可以得到min,max,mean,meduim,std等統計量,用pandas可以方便地完成,結果如下: 從上圖中可以觀察Label是否均衡,如果不均衡則需要進行over sample少數類,或者down sample多數類。我們還可以統計Numerical Variable之間的相關系數,用pandas就可以輕松獲得相關系數矩陣: 觀察相關系數矩陣可以讓你找到高相關的特征,以及特征之間的冗余度。而對于文本變量,可以統計詞頻(TF),TF-IDF,文本長度等等,更詳細的內容可以參考這里 1.2.2 可視化 人是視覺動物,更容易接受圖形化的表示,因此可以將一些統計信息通過圖表的形式展示出來,方便我們觀察和發現。比如用直方圖展示問句的頻數: 或者繪制相關系數矩陣: 常用的可視化工具有matplotlib和seaborn。當然,你也可以跳過這一步,因為可視化不是解決問題的重點。 1.3 數據預處理(Data Preprocessing) 剛拿到手的數據會出現噪聲,缺失,臟亂等現象,我們需要對數據進行清洗與加工,從而方便進行后續的工作。針對不同類型的變量,會有不同的清洗和處理方法:
1.4 特征工程(Feature Engineering) 都說特征為王,特征是決定效果最關鍵的一環。我們需要通過探索數據,利用人為先驗知識,從數據中總結出特征。
我們應該盡可能多地抽取特征,只要你認為某個特征對解決問題有幫助,它就可以成為一個特征。特征抽取需要不斷迭代,是最為燒腦的環節,它會在整個比賽周期折磨你,但這是比賽取勝的關鍵,它值得你耗費大量的時間。 那問題來了,怎么去發現特征呢?光盯著數據集肯定是不行的。如果你是新手,可以先耗費一些時間在Forum上,看看別人是怎么做Feature Extraction的,并且多思考。雖然Feature Extraction特別講究經驗,但其實還是有章可循的:
在做特征抽取的時候,我們是盡可能地抽取更多的Feature,但過多的Feature會造成冗余,噪聲,容易過擬合等問題,因此我們需要進行特征篩選。特征選擇可以加快模型的訓練速度,甚至還可以提升效果。 特征選擇的方法多種多樣,最簡單的是相關度系數(Correlation coefficient),它主要是衡量兩個變量之間的線性關系,數值在[-1.0, 1.0]區間中。數值越是接近0,兩個變量越是線性不相關。但是數值為0,并不能說明兩個變量不相關,只是線性不相關而已。 我們通過一個例子來學習一下怎么分析相關系數矩陣: 相關系數矩陣是一個對稱矩陣,所以只需要關注矩陣的左下角或者右上角。我們可以拆成兩點來看:
除此之外,還可以訓練模型來篩選特征,比如帶L1或L2懲罰項的Linear Model、Random Forest、GDBT等,它們都可以輸出特征的重要度。在這次比賽中,我們對上述方法都進行了嘗試,將不同方法的平均重要度作為最終參考指標,篩選掉得分低的特征。 1.5 建模(Modeling) 終于來到機器學習了,在這一章,我們需要開始煉丹了。
機器學習模型有很多,建議均作嘗試,不僅可以測試效果,還可以學習各種模型的使用技巧。其實,幾乎每一種模型都有回歸和分類兩種版本,常用模型有:
幸運的是,這些模型都已經有現成的工具(如scikit-learn、XGBoost、LightGBM等)可以使用,不用自己重復造輪子。但是我們應該要知道各個模型的原理,這樣在調參的時候才會游刃有余。當然,你也使用PyTorch/Tensorflow/Keras等深度學習工具來定制自己的Deep Learning模型,玩出自己的花樣。
人無完人,每個模型不可能都是完美的,它總會犯一些錯誤。為了解某個模型在犯什么錯誤,我們可以觀察被模型誤判的樣本,總結它們的共同特征,我們就可以再訓練一個效果更好的模型。這種做法有點像后面Ensemble時提到的Boosting,但是我們是人為地觀察錯誤樣本,而Boosting是交給了機器。通過錯誤分析->發現新特征->訓練新模型->錯誤分析,可以不斷地迭代出更好的效果,并且這種方式還可以培養我們對數據的嗅覺。 舉個例子,這次比賽中,我們在錯誤分析時發現,某些樣本的兩個問句表面上很相似,但是句子最后提到的地點不一樣,所以其實它們是語義不相似的,但我們的模型卻把它誤判為相似的。比如這個樣本:
為了讓模型可以處理這種樣本,我們將兩個問句的最長公共子串(Longest Common Sequence)去掉,用剩余部分訓練一個新的深度學習模型,相當于告訴模型看到這種情況的時候就不要判斷為相似的了。因此,在加入這個特征后,我們的效果得到了一些提升。
在訓練模型前,我們需要預設一些參數來確定模型結構(比如樹的深度)和優化過程(比如學習率),這種參數被稱為超參(Hyper-parameter),不同的參數會得到的模型效果也會不同。總是說調參就像是在“煉丹”,像一門“玄學”,但是根據經驗,還是可以找到一些章法的:
在Test Data的標簽未知的情況下,我們需要自己構造測試數據來驗證模型的泛化能力,因此把Train Data分割成Train Set和Valid Set兩部分,Train Set用于訓練,Valid Set用于驗證。
將Train Data按一定方法分成兩份,比如隨機取其中70%的數據作為Train Set,剩下30%作為Valid Set,每次都固定地用這兩份數據分別訓練模型和驗證模型。這種做法的缺點很明顯,它沒有用到整個訓練數據,所以驗證效果會有偏差。通常只會在訓練數據很多,模型訓練速度較慢的時候使用。
交叉驗證是將整個訓練數據隨機分成K份,訓練K個模型,每次取其中的K-1份作為Train Set,留出1份作為Valid Set,因此也叫做K-fold。至于這個K,你想取多少都可以,但一般選在3~10之間。我們可以用K個模型得分的mean和std,來評判模型得好壞(mean體現模型的能力,std體現模型是否容易過擬合),并且用K-fold的驗證結果通常會比較可靠。 如果數據出現Label不均衡情況,可以使用Stratified K-fold,這樣得到的Train Set和Test Set的Label比例是大致相同。 1.6 模型集成(Ensemble) 曾經聽過一句話,“Feature為主,Ensemble為后”。Feature決定了模型效果的上限,而Ensemble就是讓你更接近這個上限。Ensemble講究“好而不同”,不同是指模型的學習到的側重面不一樣。舉個直觀的例子,比如數學考試,A的函數題做的比B好,B的幾何題做的比A好,那么他們合作完成的分數通常比他們各自單獨完成的要高。 常見的Ensemble方法有Bagging、Boosting、Stacking、Blending。
Bagging是將多個模型(基學習器)的預測結果簡單地加權平均或者投票。Bagging的好處在于可以并行地訓練基學習器,其中Random Forest就用到了Bagging的思想。舉個通俗的例子,如下圖: 請點擊此處輸入圖片描述 老師出了兩道加法題,A同學和B同學答案的加權要比A和B各自回答的要精確。Bagging通常是沒有一個明確的優化目標的,但是有一種叫Bagging Ensemble Selection的方法,它通過貪婪算法來Bagging多個模型來優化目標值。在這次比賽中,我們也使用了這種方法。
Boosting的思想有點像知錯能改,每訓練一個基學習器,是為了彌補上一個基學習器所犯的錯誤。其中著名的算法有AdaBoost,Gradient Boost。Gradient Boost Tree就用到了這種思想。 我在1.2.3節(錯誤分析)中提到Boosting,錯誤分析->抽取特征->訓練模型->錯誤分析,這個過程就跟Boosting很相似。
Stacking是用新的模型(次學習器)去學習怎么組合那些基學習器,它的思想源自于Stacked Generalization這篇論文。如果把Bagging看作是多個基分類器的線性組合,那么Stacking就是多個基分類器的非線性組合。
Stacking可以很靈活,它可以將學習器一層一層地堆砌起來,形成一個網狀的結構,如下圖: 舉個更直觀的例子,還是那兩道加法題: 請點擊此處輸入圖片描述 這里A和B可以看作是基學習器,C、D、E都是次學習器。
在實現Stacking時,要注意的一點是,避免標簽泄漏(Label Leak)。在訓練次學習器時,需要上一層學習器對Train Data的測試結果作為特征。如果我們在Train Data上訓練,然后在Train Data上預測,就會造成Label Leak。為了避免Label Leak,需要對每個學習器使用K-fold,將K個模型對Valid Set的預測結果拼起來,作為下一層學習器的輸入。如下圖: 請點擊此處輸入圖片描述 由圖可知,我們還需要對Test Data做預測。這里有兩種選擇,可以將K個模型對Test Data的預測結果求平均,也可以用所有的Train Data重新訓練一個新模型來預測Test Data。所以在實現過程中,我們最好把每個學習器對Train Data和對Test Data的測試結果都保存下來,方便訓練和預測。 對于Stacking還要注意一點,固定K-fold可以盡量避免Valid Set過擬合,也就是全局共用一份K-fold,如果是團隊合作,組員之間也是共用一份K-fold。
Blending與Stacking很類似,它們的區別可以參考這里 1.7 后處理 有些時候在確認沒有過擬合的情況下,驗證集上做校驗時效果挺好,但是將測試結果提交后的分數卻不如人意,這時候就有可能是訓練集的分布與測試集的分布不一樣而導致的。這時候為了提高LeaderBoard的分數,還需要對測試結果進行分布調整。 比如這次比賽,訓練數據中正類的占比為0.37,那么預測結果中正類的比例也在0.37左右,然后Kernel上有人通過測試知道了測試數據中正類的占比為0.165,所以我們也對預測結果進行了調整,得到了更好的分數。具體可以看這里。 2 經驗篇 2.1 我們的方案(33th) 深度學習具有很好的模型擬合能力,使用深度學習可以較快得獲取一個不錯的Baseline,對這個問題整體的難度有一個初始的認識。雖然使用深度學習可以免去繁瑣的手工特征,但是它也有能力上限,所以提取傳統手工特征還是很有必要的。我們嘗試Forum上別人提供的方法,也嘗試自己思考去抽取特征。總結一下,我們抽取的手工特征可以分為以下4種:
我們的系統整體上使用了Stacking的框架,如下圖: 請點擊此處輸入圖片描述
比賽中發現的一些深度學習的局限: 通過對深度學習產生的結果進行錯誤分析,并且參考論壇上別人的想法,我們發現深度學習沒辦法學到的特征大概可以分為兩類:
傳統的機器學習模型和深度學習模型之間也存在表達形式上的不同。雖然傳統模型的表現未必比深度學習好,但它們學到的Pattern可能不同,通過Ensemble來取長補短,也能帶來性能上的提升。因此,同時使用傳統模型也是很有必要的。 2.2 第一名的解決方案 比賽結束不久,第一名也放出了他們的解決方案,
他們的特征總結為三個類別:
并且他們也使用了Stacking的框架,并且使用固定的k-fold:
對比以后發現我們沒有做LDA、LSI等特征,并且N-gram的粒度沒有那么細(他們用了8-gram),還有他們對Magic Feature的挖掘更加深入。還有一點是他們的Deep Learning模型設計更加合理,他們將篩選出來的手工特征也輸入到深度學習模型當中,我覺得這也是他們取得好效果的關鍵。因為顯式地將手工特征輸入給深度學習模型,相當于告訴“它你不用再學這些特征了,你去學其他的特征吧”,這樣模型就能學到更多的語義信息。所以,我們跟他們的差距還是存在的。 3 工具篇 工欲善其事,必先利其器。 Kaggle 的上常工具除了大家耳熟能詳的XGBoost之外,這里要著重推薦的是一款由微軟推出的LightGBM,這次比賽中我們就用到了。LightGBM的用法與XGBoost相似,兩者使用的區別是XGBoost調整的一個重要參數是樹的高度,而LightGBM調整的則是葉子的數目。與XGBoost 相比, 在模型訓練時速度快, 單模型的效果也略勝一籌。 調參也是一項重要工作,調參的工具主要是Hyperopt,它是一個使用搜索算法來優化目標的通用框架,目前實現了Random Search和Tree of Parzen Estimators (TPE)兩個算法。 對于 Stacking,Kaggle 的一位名為Μαριο? Μιχαηλιδη?(https://www./kazanova)的GrandMaster使用Java開發了一款集成了各種機器學習算法的工具包StackNet,據說在使用了它以后你的效果一定會比原來有所提升,值得一試。 以下總結了一些常用的工具:
4 總結與建議
5 感謝 感謝@劉思聰對本文詳細審閱,也感謝@鄭華濱對本文的指正。同時也感謝@一壺酒兮真狂士和@ChingKitWong在比賽期間帶我一起努力拼殺,真的學到了很多。 參考文獻:
|
|