轉載:https://www.toutiao.com/i6435866304363627010/git
筆者參加了由Quora舉辦的Quora Question Pairs比賽,而且得到了前1%的成績。這是筆者Kaggle首戰,因此寫下此文來系統化地梳理比賽的思路,而且和你們分享咱們參賽的一些心得。算法
Quora Question Pairs是一個天然語言(NLP)比賽,比賽的題目能夠簡單地歸納爲「預測兩個問句的語義類似的機率」。其中的樣本以下:數據結構
打Kaggle比賽的大體套路(比賽篇)框架
咱們隊伍和其餘出色隊伍的參賽經驗(經驗篇)dom
完成Kaggle比賽須要學會哪些實用的工具(工具篇)機器學習
1.1 分析題目ide
拿到賽題之後,第一步就是要破題,咱們須要將問題轉化爲相應的機器學習問題。Kaggle最多見的機器學習問題類型有:函數
迴歸問題工具
分類問題(二分類、多分類、多標籤):多分類只需從多個類別中預測一個類別,而多標籤則須要預測出多個類別。性能
好比Quora的比賽就是二分類問題,由於只須要判斷兩個問句的語義是否類似。
1.2 數據分析
所謂數據挖掘,固然是要從數據中去挖掘咱們想要的東西,咱們須要經過人爲地去分析數據,才能夠發現數據中存在的問題和特徵。咱們須要在觀察數據的過程當中思考如下幾個問題:
數據應該怎麼清洗和處理纔是合理的
根據數據的類型能夠挖掘怎樣的特徵
數據中的哪些特徵會對標籤的預測有幫助
1.2.1 統計分析
對於數值類變量,咱們能夠獲得min,max,mean,meduim,std等統計量,用pandas能夠方便地完成,結果以下:
從上圖中能夠觀察Label是否均衡,若是不均衡則須要進行over sample少數類,或者down sample多數類
咱們還能夠統計數值類變量之間的相關係數,用pandas就能夠輕鬆得到相關係數矩陣:觀察相關係數矩陣可讓你找到高相關的特徵,以及特徵之間的冗餘度。而對於文本變量,能夠統計詞頻(TF),TF-IDF,文本長度等等
1.2.2 可視化
人是視覺動物,更容易接受圖形化的表示,所以能夠將一些統計信息經過圖表的形式展現出來,方便咱們觀察和發現。好比用直方圖展現問句的頻數或者繪製相關係數矩陣:經常使用的可視化工具備matplotlib和seaborn。固然,你也能夠跳過這一步,由於可視化不是解決問題的重點。
1.3 數據預處理
剛拿到手的數據會出現噪聲,缺失,髒亂等現象,咱們須要對數據進行清洗與加工,從而方便進行後續的工做。針對不一樣類型的變量,會有不一樣的清洗和處理方法:
對於數值型變量,須要處理離羣點,缺失值,異常值等狀況
對於類別型變量,能夠轉化爲one-hot編碼、實體嵌入、哈希編碼
文本數據是難處理的數據類型,有垃圾字符,錯別字詞,數學公式,不統一單位和日期格式等。咱們還須要處理標點符號,分詞,去停用詞,對於英文文本可能還要詞性還原(lemmatize),抽取詞幹(stem)等等。
1.4 特徵工程(Feature Engineering)
都說特徵爲王,特徵是決定效果最關鍵的一環。咱們須要經過探索數據,利用人爲先驗知識,從數據中總結出特徵。
1.4.1 特徵抽取(Feature Extraction)
咱們應該儘量多地抽取特徵,只要你認爲某個特徵對解決問題有幫助,它就能夠成爲一個特徵。特徵抽取須要不斷迭代,是最爲燒腦的環節,它會在整個比賽週期折磨你,但這是比賽取勝的關鍵,它值得你耗費大量的時間。
那問題來了,怎麼去發現特徵呢?光盯着數據集確定是不行的。若是你是新手,能夠先耗費一些時間在Forum上,看看別人是怎麼作Feature Extraction的,而且多思考。雖然Feature Extraction特別講究經驗,但其實仍是有章可循的:
對於Numerical Variable,能夠經過線性組合、多項式組合來發現新的Feature
對於文本數據,有一些常規的Feature。好比,文本長度,Embeddings,TF-IDF,LDA,LSI等,你甚至能夠用深度學習提取文本特徵(隱藏層)
若是你想對數據有更深刻的瞭解,能夠經過思考數據集的構造過程來發現一些magic feature,這些特徵有可能會大大提高效果。在Quora此次比賽中,就有人公佈了一些magic feature
經過錯誤分析也能夠發現新的特徵,見1.5.2小節
1.4.2 特徵選擇(Feature Selection)
作特徵抽取,儘量地抽取更多的Feature,但過多的Feature會形成冗餘,噪聲,容易過擬合等問題,所以咱們需特徵篩選。特徵選擇能夠加快模型的訓練速度,甚至還能夠提高效果。特徵選擇的方法多種多樣,最簡單的是相關度係數(Correlation coefficient),它主要是衡量兩個變量之間的線性關係,數值在[-1.0, 1.0]區間中。數值越是接近0,兩個變量越是線性不相關。可是數值爲0,並不能說明兩個變量不相關,只是線性不相關而已。
咱們經過一個例子來學習一下怎麼分析相關係數矩陣:
相關係數矩陣是一個對稱矩陣,因此只須要關注矩陣的左下角或者右上角。咱們能夠拆成兩點來看:
Feature和Label的相關度能夠看做是該Feature的重要度,越接近1或-1就越好
Feature和Feature之間的相關度要低,若是兩個Feature的相關度很高,就有可能存在冗餘
除此以外,還能夠訓練模型來篩選特徵,好比帶L1或L2懲罰項的Linear Model、Random Forest、GDBT等,它們均可以輸出特徵的重要度。在此次比賽中,咱們對上述方法都進行了嘗試,將不一樣方法的平均重要度做爲最終參考指標,篩選掉得分低的特徵。
1.5 模型創建(Modeling)
1.5.1 模型
機器學習模型有不少,建議均做嘗試,不只能夠測試效果,還能夠學習各類模型的使用技巧。其實,幾乎每一種模型都有迴歸和分類兩種版本,經常使用模型有:
KNN
SVM
帶懲罰項的Linear Model
ExtraTree
RandomForest
Gradient Boost Tree
Neural Network
這些模型都已經有現成的工具(如scikit-learn、XGBoost、LightGBM等)可使用。可是咱們應該要知道各個模型的原理,這樣在調參的時候纔會遊刃有餘。你也使用PyTorch/Tensorflow/Keras等深度學習工具來定製本身的Deep Learning模型。
1.5.2 錯誤分析
人無完人,每一個模型不可能都是完美的,它總會犯一些錯誤。爲了解某個模型在犯什麼錯誤,咱們能夠觀察被模型誤判的樣本,總結它們的共同特徵,咱們就能夠再訓練一個效果更好的模型。這種作法有點像後面Ensemble時提到的Boosting,可是咱們是人爲地觀察錯誤樣本,而Boosting是交給了機器。經過錯誤分析->發現新特徵->訓練新模型->錯誤分析,能夠不斷地迭代出更好的效果,而且這種方式還能夠培養咱們對數據的嗅覺。
舉個例子,此次比賽中,咱們在錯誤分析時發現,某些樣本的兩個問句表面上很類似,可是句子最後提到的地點不同,因此其實它們是語義不類似的,但咱們的模型卻把它誤判爲類似的。好比這個樣本:
Question1: Which is the best digital marketing institution in banglore?
Question2: Which is the best digital marketing institute in Pune?
爲了讓模型能夠處理這種樣本,咱們將兩個問句的最長公共子串(Longest Common Sequence)去掉,用剩餘部分訓練一個新的深度學習模型,至關於告訴模型看到這種狀況的時候就不要判斷爲類似的了。所以,在加入這個特徵後,咱們的效果獲得了一些提高。
1.5.3 調參
訓練模型前,咱們須要預設一些參數來肯定模型結構(好比樹的深度)和優化過程(好比學習率),這種參數被稱爲超參(Hyper-parameter),不一樣的參數會獲得的模型效果也會不一樣。老是說調參就像是在「煉丹」,像一門「玄學」,可是根據經驗,仍是能夠找到一些章法的:
根據經驗,選出對模型效果影響較大的超參
按照經驗設置超參的搜索空間,好比學習率的搜索空間爲[0.001,0.1]
選擇搜索算法,好比Random Search、Grid Search和一些啓發式搜索的方法
驗證模型的泛化能力:詳見下一小節
1.5.4 模型驗證(Validation)
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
1.6.1 Bagging
Bagging是將多個模型(基學習器)的預測結果簡單地加權平均或者投票。Bagging的好處在於能夠並行地訓練基學習器,其中Random Forest就用到了Bagging的思想。舉個通俗的例子,以下圖:
老師出了兩道加法題,A同窗和B同窗答案的加權要比A和B各自回答的要精確。Bagging一般是沒有一個明確的優化目標的,可是有一種叫Bagging Ensemble Selection的方法,它經過貪婪算法來Bagging多個模型來優化目標值。
Bagging Ensemble Selection:http://www.cs.cornell.edu/~alexn/papers/shotgun.icml04.revised.rev2.pdf1.6.2 Boosting
Boosting的思想有點像知錯能改,每訓練一個基學習器,是爲了彌補上一個基學習器所犯的錯誤。其中著名的算法有AdaBoost,Gradient Boost。Gradient Boost Tree就用到了這種思想。我在1.2.3節的錯誤分析中提到Boosting,錯誤分析->抽取特徵->訓練模型->錯誤分析,這個過程就跟Boosting很類似。
1.6.3 Stacking
Stacking是用新的模型(次學習器)去學習怎麼組合那些基學習器,它的思想源自於Stacked Generalization這篇論文。若是把Bagging看做是多個基分類器的線性組合,那麼Stacking就是多個基分類器的非線性組合。
Stacked Generalization論文:http://www.machine-learning.martinsewell.com/ensembles/stacking/Wolpert1992.pdf
Stacking能夠很靈活,它能夠將學習器一層一層地堆砌起來,造成一個網狀的結構,以下圖:
舉個更直觀的例子,仍是那兩道加法題:
這裏A和B能夠看做是基學習器,C、D、E都是次學習器
Stage1: A和B各自寫出了答案
Stage2: C和D偷看了A和B的答案,C認爲A和B同樣聰明,D認爲A比B聰明一點。他們各自結合了A和B的答案後,給出了本身的答案
Stage3: E偷看了C和D的答案,E認爲D比C聰明,隨後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。
若是想具體瞭解爲何須要固定K-fold,請看這裏:https://mlwave.com/kaggle-ensembling-guide/
1.6.4 Blending
Blending與Stacking很相似
1.7 後處理
有些時候在確認沒有過擬合的狀況下,驗證集上作校驗時效果挺好,可是將測試結果提交後的分數卻不如人意,這時候就有多是訓練集的分佈與測試集的分佈不同而致使的。這時候爲了提升LeaderBoard的分數,還須要對測試結果進行分佈調整。
好比此次比賽,訓練數據中正類的佔比爲0.37,那麼預測結果中正類比例也在0.37左右,而後Kernel上有人經過測試知道了測試數據中正類的佔比爲0.165,因此咱們也對預測結果進行了調整(方法:我的以爲能夠調節斷定正負的閾值),獲得了更好的分數。
2 經驗篇
2.1 咱們的方案
深度學習具備很好的模型擬合能力,使用深度學習能夠較快得獲取一個不錯的Baseline,對這個問題總體的難度有一個初始的認識。雖然使用深度學習能夠免去繁瑣的手工特徵,可是它也有能力上限,因此提取傳統手工特徵仍是頗有必要的。咱們嘗試Forum上別人提供的方法,也嘗試本身思考去抽取特徵。總結一下,咱們抽取的手工特徵能夠分爲如下4種:
Text Mining Feature, 好比句子長度;兩個句子的文本類似度,如N-gram的編輯距離,Jaccard距離等;兩個句子共同的名詞,動詞,疑問詞等
Embedding Feature, 預訓練好的詞向量相加求出句子向量,而後求兩個句子向量的距離,好比餘弦類似度、歐式距離等等
Vector Space Feature,用TF-IDF矩陣來表示句子,求類似度
Magic Feature, 是Forum上一些選手經過思考數據集構造過程而發現的Feature,這種Feature每每與Label有強相關性,能夠大大提升預測效果
咱們的系統總體上使用了Stacking的框架,以下圖:
Stage1: 將兩個問句與Magic Feature輸入Deep Learning中,將其輸出做爲下一層的特徵(這裏的Deep Learning至關於特徵抽取器),咱們一共訓練了幾十個Deep Learning Model
Stage2: 將Deep Learning特徵與手工抽取的幾百個傳統特徵拼在一塊兒,做爲輸入,在這一層,咱們訓練各類模型,有成百上千個
Stage3: 上一層的輸c進行Ensemble Selection
比賽中發現的一些深度學習的侷限:
經過對深度學習產生的結果進行錯誤分析,而且參考論壇上別人的想法,咱們發現深度學習沒辦法學到的特徵大概能夠分爲兩類:
對於一些數據的Pattern,在Train Data中出現的頻數不足以讓深度學習學到對應的特徵,因此咱們須要經過手工提取這些特徵
因爲Deep Learning對樣本作了獨立同分布假設(iid),通常只能學習到每一個樣本的特徵,而學習到數據的全局特徵,好比TF-IDF這一類須要統計全局詞頻才能獲取的特徵,所以也須要手工提取這些特徵
傳統的機器學習模型和深度學習模型之間也存在表達形式上的不一樣。雖然傳統模型的表現未必比深度學習好,但它們學到的Pattern可能不一樣,經過Ensemble來取長補短,也能帶來性能上的提高。所以,同時使用傳統模型也是頗有必要的。
2.2 第一名的解決方案
比賽結束不久,第一名也放出了他們的解決方案,
咱們來看看他們的作法:https://www.kaggle.com/c/quora-question-pairs/discussion/34355
他們的特徵總結爲三個類別:
Embedding Feature
Text Mining Feature
Structural Feature(他們本身挖掘的Magic Feature)
而且他們也使用了Stacking的框架,而且使用固定的k-fold:
Stage1: 使用了Deep Learning,XGBoost,LightGBM,ExtraTree,Random Forest,KNN等300個模型
Stage2: 用了手工特徵和第一層的預測和深度學習模型的隱藏層,而且訓練了150個模型
Stage3: 使用了分別是帶有L1和L2的兩種線性模型
Stage4: 將第三層的結果加權平均
對比之後發現咱們沒有作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.kaggle.com/kazanova)的GrandMaster使用Java開發了一款集成了各類機器學習算法的工具包StackNet,聽說在使用了它之後你的效果必定會比原來有所提高,值得一試。
如下總結了一些經常使用的工具:
Numpy | 必用的科學計算基礎包,底層由C實現,計算速度快
Pandas | 提供了高性能、易用的數據結構及數據分析工具
NLTK | 天然語言工具包,集成了不少天然語言相關的算法和資源
Stanford CoreNLP | Stanford的天然語言工具包,能夠經過NLTK調用
Gensim | 主題模型工具包,可用於訓練詞向量,讀取預訓練好的詞向量
scikit-learn | 機器學習Python包 ,包含了大部分的機器學習算法
XGBoost/LightGBM | Gradient Boosting 算法的兩種實現框架
PyTorch/TensorFlow/Keras | 經常使用的深度學習框架
StackNet | 準備好特徵以後,能夠直接使用的Stacking工具包
Hyperopt | 通用的優化框架,可用於調參
4 總結與建議
參加某個比賽前,要先衡量本身的機器資源可否足夠支撐你完成比賽。好比一個有幾萬張圖像的比賽,而你的顯存只有2G,那很明顯你是不適合參加這個比賽的。當你選擇了一個比賽後,能夠先「熱熱身」,稍微熟悉一下數據,粗略地跑出一些簡單的模型,看看本身在榜上的排名,而後再去慢慢迭代。
Kaggle有許多大牛分享Kernel, 有許多Kernel有對於數據精闢的分析,以及一些baseline 模型, 對於初學者來講是很好的入門資料。在打比賽的過程當中能夠學習別人的分析方法,有利於培養本身數據嗅覺。甚至一些Kernel會給出一些data leak,會對於比賽提升排名有極大的幫助。
其次是Kaggle已經舉辦了不少比賽, 有些比賽有相似之處, 好比此次的Quora比賽就與以前的Home Depot Product Search Relevance(https://www.kaggle.com/c/home-depot-product-search-relevance)有類似之處,而以前的比賽前幾名已經放出了比賽的idea甚至代碼,這些均可以借鑑。
另外,要足夠地重視Ensemble,此次咱們組的最終方案實現了paper " Ensemble Selection from Libraries of Models" 的想法,因此有些比賽可能還須要讀一些paper,尤爲對於深度學習相關的比賽,最新paper,最新模型的做用就舉足輕重了。
並且,將比賽代碼的流程自動化,是提升比賽效率的一個關鍵,可是每每初學者並不能很好地實現本身的自動化系統。個人建議是初學者不要急於構建自動化系統,當你基本完成整個比賽流程後,天然而然地就會在腦海中造成一個框架,這時候再去構建你的自動化系統會更加容易。
最後,也是最重要的因素之一就是時間的投入,對於此次比賽, 咱們投入了差很少三個多月,涉及到了對於各類可以想到的方案的嘗試。尤爲最後一個月,基本上天天除了睡覺以外的時間都在作比賽。因此要想在比賽中拿到好名次,時間的投入必不可少。另外對於國外一些介紹kaggle比賽的博客(好比官方博客)也須要了解學習,至少能夠少走彎路,本文的結尾列出了一些參考文獻,都值得細細研讀。
最後的最後,請作好心理準備,這是一場持久戰。由於比賽會給你帶來壓力,也許過了一晚,你的排名就會一落千丈。還有可能形成出現失落感,焦慮感,甚至失眠等症狀。但請你相信,它會給你帶來意想不到的驚喜,認真去作,你會以爲這些都是值得的。
參考文獻:
1.Paper: Ensemble Selection from Libraries of Models :http://link.zhihu.com/?target=http%3A//www.cs.cornell.edu/%7Ealexn/papers/shotgun.icml04.revised.rev2.pdf
2. Kaggle 數據挖掘比賽經驗分享:https://zhuanlan.zhihu.com/p/26820998
3. Kaggle Ensembling Guide:http://link.zhihu.com/?target=https%3A//mlwave.com/kaggle-ensembling-guide/