Kaggle 首戰拿銀總結 | 入門指導 (長文、乾貨)

轉自:https://blog.csdn.net/jdbc/article/details/72468001

 

轉自:第一次參加Kaggle拿銀總結

作者:ScarletPan

另一篇文章從0到1走進 Kaggle


我的比賽代碼已經放到github --> Kaggle-Rental-Listing-Inquireies

在這篇博客開始之前,我必須感謝導師給我提供服務器資源,@Fenix Lin學長從他自身經驗出發耐心地爲我解答一些困惑,素未謀面的@Wille學長的一篇非常優秀的博文如何在Kaggle 首戰中進入前 10%幫助入門,以及廣大Kaggler的無私分享,我確實在Kaggle舉行的這場Rental Listing Inquiries比賽中收益良多,獲得了不少知識。作爲第一次參加比賽,獲得了Top 5%的成績已經讓我非常滿意了。

這篇文章的目的是介紹自己第一次參加Kaggle的心歷路程,總結遇到的問題和解決思路,爲自己以後參賽做準備。同時這篇文章也可以作爲一個初學者的入門Kaggle的參考,如果想要在入門kaggle的時候拿到一個好的名次,可以參考我的一些方法實踐。本文可以隨意轉載,但務必註明出處和作者, 並且發郵件[email protected]通知與我。


初識Kaggle

什麼是Kaggle

從剛接觸machine learning的時候就有在學長口中、博文中、社區中聽到過它的名字,當初我對它的理解還比較浮淺,只是知道是一個數據比賽的平臺,有很多公開的數據集,比如大二寒假做的第一個ML練手項目就是一個用word2vec進行情感分析的Tutorial級比賽Bag of Words Meets Bags of Popcorn,並且寫了一個Research report。這過程中只用到了教程和數據集。

後來重新接觸Kaggle才發現,它的價值所在是各種高質量的比賽,以及每場比賽下面的社區討論(包括比賽中的分享、答疑,和比賽後的top solution分享),因此如果想要獲得關於數據挖掘,機器學習實戰經驗的話,打一場kaggle比賽絕對是一個高回報的工作。

因爲還是學生,不知道kaggle比賽究竟是否會爲自己求職工作有舉足輕重的影響,但是單從Kaggle被google收購一點來看,它會在行業內一點點提升影響力的。

比賽組織

一場比賽通常持續2~3個月,在比賽的簡介中會有規則、評價指標(比如這場比賽爲mlogloss),時間軸等信息。另外還有數據區、Kernel區(一些Kagglers在kaggle上成功運行的ipython notebook或者代碼),Discussion(討論區),LeaderBoard(LB,分爲公開的用戶提交可以顯示結果的榜單,和非公開的比賽結束後確定最終排名的榜單),當然還有提交區(一般爲一定格式的csv文件提交)。

另外就是獎牌問題,一般來講在1000+量級的比賽中,top 10+ 0.2%爲金牌,5%爲銀牌,10%爲銅牌,這裏有更具體的獎牌發放方式。

討論區

個人認爲,如果想在入門Kaggle階段就獲得一個好的成績的話,關注discussion是非常重要的,會有很多人分享自己的思路、困惑甚至代碼和結果。有時候,一場比賽中比較關鍵的feature可能就是從討論區中獲得的,比如Two Sigma Connect: Rental Listing Inquiries這場比賽的最後幾天,我以爲自己特徵提取得已經差不多了,沒有任何idea了的時候,一個來自討論區magic feature從天而降,從而使得榜單大變,一夜之間我的排名從70多掉到了120多。


數據探索和可視化(EDA)

首先拿到一個比賽題目,你需要下決心是否參加這個比賽,對我個人而言最重要的無非兩點 1. 是不是有rank point,也就是獎牌, 2. 數據集是否令我滿意。 因此對數據的探索首先需要你從Kaggle網站上查看數據的簡介,並把數據下載下來。比如Rental Listing Inquiries包含了80G的圖片數據,和幾份json文件。

我們將下載下來的train.csv用python pandas 打開,取少量樣本進行觀測

 


 
  1. import pandas as pd

  2. train = pd.read_json("input/train.json")

  3. train.sample(2)

 

拋開圖片數據不談,我們可以看到給定的數據裏包含多種多樣的feature:

  • 數值型feature

    • bathrooms
    • bedrooms
    • price
  • 高勢集類別(High Categorical)型feature

    • building_id
    • display_address
    • manager_id
    • street_address
  • 時間型feature

    • created
    • 地理位置型feature
    • longitude
    • latitude
  • 文本feature

    • description
  • 稀疏特徵集feature

    • features
  • id型feature

    • listing_id
    • index

我們看到有這麼多不同的feature,一看幾乎每個feature都有深度挖掘的價值,何況還有80G的圖片feature,無疑是讓人興奮的,因此我選擇了這個比賽,因爲它的數據集的確讓我舒心。

另外一定要搞明白的一件事是這場比賽是一個預測比賽還是分類比賽,我們能看到最重要預測的是用戶的interest_level,分爲low,medium,high三級,很顯然是個分類問題了。

接下來的是就是對數據進行可視化探索了,我因爲是初期參賽的,所以自己做了一份可視化方案,從中可以發現很多有趣的分佈、outlier等。在這裏推薦三份在比賽中分享出來的比較好的EDA:


提取基礎特徵+模型訓練

有了之前數據探索的基礎,我們很快能提取到一些基礎的feature,比如數值型feature進行簡單的加減乘除,類別型feature用id順序編碼,稀疏特徵集用one-hot編碼,時間特徵生成年、月、日等。將一些基礎的特徵轉換成相應的輸入input_X矩陣後,再將label也轉換成數值形式:

 


 
  1. target_num_map = {'high':0, 'medium':1, 'low':2}

  2. y = data["interest_level"].apply(lambda x: target_num_map[x])

 

懂機器學習的人都知道,有了這些(X,y)對,我們就可以進行模型訓練了。

我們用cross-validation(CV)的成績來判斷我們本地的實驗結果,也就是將(X,y)訓練集拆分成訓練和驗證集,訓練相應分類器對訓練集擬合,再在驗證集上進行loss的計算來評估模型的好壞。

常見的分類器有Logistic Classifier,SVM, NN softmax,Random Forest等。但是在kaggle上用的比較多的還是一些封裝好的庫,如sklearn裏的各種分類器,大名鼎鼎的xgboost,最近嶄露頭角的lightgbm等。

早就聽聞xgboost的好用,我就直接在電腦上pip了xgboost,作爲我接下來一兩個月以來的核心分類器。將原先的(X,y)對中的訓練部分輸入xgboost進行fit,然後用驗證部分predict計算mlogloss。

至此爲止,比賽初期的第一個模型就已經訓練好了。


跑出一個能提交的結果

訓練完一個比較好的模型之後,就可以對測試集進行預測了,首先將訓練集(X,y)對輸入xgboost中重新訓練,然後對測試集也像對訓練集一樣進行特徵處理,預測出來的結果按照比賽指定的格式保存到文件(在這裏還是建議用pandas),即可提交。

第一次提交意味着你正式進入比賽,提交的結果會在Leader Board上顯示你當前的排名,當然這個排名只起到參考作用,因爲你提交上去的大部分結果kaggle都沒有進行評估。


特徵工程(FE)

在一系列的初始操作以後,你就要踏上FE的漫漫長征了。本人斷斷續續在數據清洗、特徵提取上做了約兩個多月,在比賽最後一段時間模型融合完畢後還在繼續地尋找、測試新的特徵。後期評論區中magic feature的出現,讓每個人的預測結果好了0.01~0.02個點。不得不說,特徵工程纔是Kaggle比賽獲勝的關鍵所在,因此初學者耗費大量精力在這上面是沒錯的。而本博文也是重點想講一下自己發現新特徵的一些心歷路程。

在對一些基礎的特徵進行生成之後,我開始了漫長地測試特徵的長征路,測試的思路我後來發現並不是很好,因爲是通過新增加一個或幾個feature,如果cv分數上去了,就增加這個feature,如果cv分數沒有上去,就捨棄這個feature,也就是相當於貪心驗證。這樣做的弊處在於,如果之前被捨棄的feature和之後被捨棄的feature聯合在一起纔會有正面影響,就相當於你錯過了兩個比較好的feature。因此特徵的選擇和聯合顯得非常關鍵。

在比賽階段,花費大量力氣去創建一個feature,到頭來卻選擇放棄這個feature的事情很常見,我後期的特徵有很多是新添加的,舊有的一些特徵並沒有保留。接下來就讓我總結一下這場比賽中有哪些“好”的feature,爲以後的比賽提供靈感和經驗。

  • 數值型feature的簡單加減乘除

這個乍一看彷彿沒有道理可言,但是事實上卻能挖掘出幾個feature之間的內在聯繫,比如這場比賽中提供了bathrooms和bedrooms的數量,以及價格price,合租用戶可能會更關心每個臥室的價格,即bathrooms / price,也會關心是不是每個房間都會有一個衛生間bathrooms / price ,這些數值型feature之間通過算數的手段建立了聯繫,從而挖掘出了feature內部的一些價值,分數也就相應地上去了。

  • 高勢集類別(High Categorical)進行經驗貝葉斯轉換成數值feature

什麼是High Categorical的特徵呢?一個簡單的例子就是郵編,有100個城市就會有好幾百個郵編,有些房子坐落在同一個郵編下面。很顯然隨着郵編的數量增多,如果用簡單的one-hot編碼顯然效果不太好,因此有人就用一些統計學思想(經驗貝葉斯)將這些類別數據進行一個map,得到的結果是數值數據。在這場比賽中有人分享了一篇paper裏面就提到了具體的算法。詳細就不仔細講了,用了這個encoding之後,的確效果提升了很多。那麼這場比賽中哪些數據可以進行這樣的encoding呢,只要滿足下面幾點:1. 會重複,2. 根據相同的值分組會分出超過一定數量(比如100)的組。也就是說building_id, manager_id, street_address, display_address都能進行這樣的encoding,而取捨就由最後的實驗來決定了。

  • 時間特徵

針對於時間數據來講,提取年、月、日、星期等可能還是不夠的,有另外一些points可以去思考,用戶的興趣跟發佈時間的久遠是否有關係?可以構造如下的feature來進行測試:

 


 
  1. data["latest"] = (data["created"]- data["created"].min())

  2. data["passed"] = (data["created"].max()- data["created"])

 

可以看到latest指的是從有數據開始到該房創建爲止一共過去了多少時間,而passed則是該房記錄創建爲止到最後有記錄的時候一共過去了多少時間。

另外針對於時間特徵還可以用可視化的方式來與其他特徵建立聯繫,比如我們觀察listing_id與時間變化到底有怎樣的聯繫,能夠繪製出如下的圖來:

可能簡單的相除就能獲得很好的結果

  • 地理位置特徵

想到地理位置,就會想到聚類,一個簡單的方式將每個房子劃分到同一塊區域中去;除了聚類以外,算出幾個中心點座標,計算曼哈頓距離或者歐式距離可能都會有神奇的效果。

  • 文本特徵

實話說自己是看中這次比賽中有文本數據才參加的,因此在文本挖掘中做了很大的努力,比如提取關鍵詞、情感分析、word embedding聚類之類都嘗試過,但效果都不是很好, 對於文本的特徵的建議還是去找出一些除了停用詞以外的高頻詞彙,尋找與這個房屋分類問題的具體聯繫。

  • 圖片特徵

除了最後爆料出來的magic feature(後文會提到)以外,我只用了一個房子有幾個照片這個信息。討論區中都說對於圖片特徵用CNN提取、簡單特徵提取之類的效果都不是很好。

  • 稀疏特徵集

其實就相當於一系列標籤,不同標籤的個數也是挺多的,本次比賽我只是簡單地採用了counterEncoding的方式進行one-hot編碼。值得一提的是,有些標籤是可以合併的,比如cat allowed 和 dog allowed可以合併成爲 pet allowed,我在這場比賽中手工地合併了一些feature數據,最終結果略微有所提升。

  • 特徵重要程度(feature importance)

在樹結構的分類器比如randomforest、xgboost中最後能夠對每個特徵在分類上面的重要程度進行一個評估。這時候如果已經選定了一些feature進行訓練了之後,查看feature importance的反饋是非常重要的,比如本場比賽制勝的關鍵是運用manager_id這個feature,而它的feature importance反饋結果也是非常高。通過對重要特徵的重新再提取特徵,能夠發現很多有意思的新特徵,這纔是用FE打好一場比賽的關鍵所在。


下面列出了一些比賽結束後獲勝者分享的idea,這大概是我這場比賽中獲益最大的一塊地方了。

  • Top #1 solution @plantsgo

主要是針對manager_id生成了非常多的feature。如根據不同時間出現的manager_id判斷一個manager是否活躍(manager與time進行group,manager掌管有幾個不同的房子(manager與building_id進行group)、平均每天處理多少房子(比值)、活動範圍(同個manager掌管的房子的最大最小經緯度group),經理的開價程度(選擇bedroom和bathroom作爲房子型號指標,把相同房型的均價來衡量經理對於所有房子的開價程度),對經緯度進行聚類再計算每個區域中有多少個manager競爭、一個manager同時經營幾個區域、在同個區域中manager的開價水平等。從Top 1選手分享的代碼來看,其對於manager的各種處理的確是讓人大開眼界。

  • Top #2 solution @Faron

從更爲經驗老道的選手給出了一些特徵提取建議。其中有一類被作者稱爲"Likelihood Features",他對High Cardinal Categorical的特徵用了一些額外的條件概率來計算其似然值,如p(y|manager_id, bathrooms)等,並且進行了點積操作來計算出一個合適的encoding值(類似於先前討論區中出現的manager_skills,同時爲了防止過擬合對這些似然估計出來的feature創建了2層嵌套。另外還有一種對我啓發比較大的feature是對description出現頻率最高的15k單詞進行一個one-hot深度xgboost訓練,將這個訓練出來模型的預測結果作爲description的encoding。

  • Top #3 solution @Little Boat

其FE的第一部分給出了group的一套方案,類似於我自己FE中的group方法。第二部分使用了magic feature相關的feature,方法與第一部分類似

  • Top #9 solution @James Trotman

沒有細說,但是列出了一個feature name的詳單,希望以後沒有idea的時候能從中找到一些insight

  • Top #11 solution @KazAnova

KazAnova無疑是這場比賽中的明星選手,他分享了對初學者模型融合比較關鍵的Stack-Net,以及對最後榜單變動起到決定性作用的magic feature。幾乎所有在榜上的Kagglers都要向他致敬。同時在FE這一塊,他注意到了數據集中存在很多類似的數據(僅僅在價格上有區別),因此他建立了不同的group,並在這些group間創建了很多aggregated features,比如最高的price,平均price等

  • Top #12 solution @b.e.s

用到了基於高勢集類別數據的group的一些統計量。

  • Top #13 solution @qianqian

也是用了很多基於manager_id group的統計feature。

模型調參(Grid Search)

模型調參的話,能夠在FE完之後爲你提升0.001~0.002分數,因此如何爲我們的分類器,比如xgboost選擇好正確的參數是非常關鍵的。

比較常用的是進行Grid Search,從你的輸入組合中暴力地搜索cv結果最優的組合。我一般會設定一個learning rate,然後嘗試不同的參數組合,取最優值,因爲訓search的代價比較高,最好選擇一定範圍,比如你事先cv的時候知道estimater會在700~1000的範圍內,那就不要search這個範圍以外的值了。

模型融合

如果你沒有idea了的話,就模型融合吧!模型融合是能夠快速提高比賽成績的捷徑,現在的比賽幾乎沒有人不用到這個技巧,通常獲勝者會對很多很多模型進行融合,並且會選擇不同的模型融合的方式。這裏有一篇非常好的模型融合解析博文,相信每個看過它的人都會對模型融合有一個清楚的瞭解

本次比賽中我使用了兩種模型融合方式,一種是Averaging,一種是Stacking。

先來說說Stacking,因爲這場比賽一名貢獻比較大的選手分享了一個叫StackNet的庫,作爲新手我就直接用了。首先我用我的xgboost cv集交叉預測出結果作爲feature的一部分放到train data中,再對test data進行預測的結果作爲feature的一部分放到test data中,再在第二層上選擇了Logistic Classifer,GradientBoostingClassifer,AdaBoostClassifer,NNSoft-maxClassfier,RandomForestClassifer等進行交叉預測,第三層選取了一個randomForest作爲最後的結果訓練和預測。Stacking主要增多了模型的diversity,使我的成績上升了至少0.003的量級。

然後是Averaging,之前提到過Stacking需要交叉預測,我就選取了10組隨機種子分別對訓練集進行10-kfold交叉預測取平均,以及每個flod訓練預測的時候我都對我的xgboost選取5個隨機種子取平均。也就是說,在第一層Stacking的CV集交叉預測時我總共訓練了500個模型進行平均。分數的提升大約在0.002左右。

直到比賽結束看了排名靠前的選手的模型融合後,才發現自己對於模型融合只是做了一點微小的工作,提升空間還非常大。詳情可以看FE部分分享的solution鏈接。

Tricks

在這場比賽中有一名在一開始的兩個月一直遙遙領先的選手爆出這個比賽有個magic feature,大家陷入了瘋狂找這個feature的過程中,直到那位分享了StackNet的選手分享出了這個magic feature:80G圖片數據每個文件夾的創建時間,於是榜單大變,我一覺醒來後發現自己掉了很多就發現到了不對勁,便迅速加入到這個magic feature瘋狂屠榜的大軍中,從這裏可以看見,一個信息量巨大的feature如果被發現的話,對比賽成績會帶來多麼大的影響。

有一些group的feature能夠起到非常重要的作用,詳細見我比賽後發表的一個小樣例discussion topic。但是一定要防止過擬合。

總結

這篇博文還有一些關鍵的點沒有涉及到,比如數據的清洗,有些數據在記錄中似乎是不同的,但是意思是一樣的,就應該歸位同一個類別,還有就是清除一些outlier等。

對這個比賽的top solution總結得還是沒到位,基本沒有coding實現他們的idea過。由於課程壓力比較大,等到時候空了的時候再好好整理。

另外還有就是需要持之以恆地打這個比賽,因爲你以爲你idea都沒有了,模型調參、融合完畢了的時候,可能大家都找出了另一個"magic feature",輕鬆地把你擠出獎牌的範圍內了。

最後,Kaggle is fun!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章