如何從零開始準備Kaggle大數據競賽?

在學習(xi) 過深度學習(xi) 的基礎知識之後,參與(yu) 實踐是繼續提高自己的最好途徑。本文將帶你進入全球最大機器學習(xi) 競賽社區 Kaggle,教你如何選擇自己適合的項目,構建自己的模型,提交自己的第一份成績單。

本文將介紹數據科學領域大家都非常關(guan) 心的一件事。事先完成一門機器學習(xi) MOOC 課程並對 Python 有一些基礎知識有助於(yu) 理解文本,但沒有也沒關(guan) 係。本文並不會(hui) 向大家展示令人印象深刻的成果,而是回顧基礎知識,試圖幫助初學者找到方向。

文章結構:

  • 介紹

  • Kaggle 綜述

  • 建立自己的環境

  • 預測房價(jia) 競賽簡介

  • 加載和檢查數據

  • 我們(men) 的模型:決(jue) 策樹介紹、偏差-方差權衡、隨機森林

  • 預處理數據

  • 整合並提交結果

介紹

目前,我們(men) 能在網上找到很多高質量的免費機器學習(xi) 教程,如 MOOC。一年以前,我在 Udacity 接觸了「機器學習(xi) 入門」課程,我認為(wei) 它對於(yu) 新手來說非常友好。在這裏,我學到了機器學習(xi) 基礎概念、很多流行算法,以及 scikit-learn 的 API。在完成課程以後,我非常希望學到更多,但陷入了短暫的迷茫。

在做完一番研究後,我認為(wei) 下一步最優(you) 的選擇是進軍(jun) Kaggle,它是穀歌旗下的一個(ge) 預測模型競賽平台。沒什麽(me) 比自己動手進行實踐更好了!

初次嚐試 Kaggle 競賽是很緊張刺激的,很多時候也伴隨著沮喪(sang) (得到好成績之後這種感覺似乎還加深了!),本文將著重介紹如何入門並開始你的第一場 Kaggle 競賽,在這個(ge) 過程中盡快成長。

Kaggle 綜述

從(cong) 零開始,教初學者如何征戰Kaggle競賽

房價(jia) 競賽登錄頁麵。

(如果你已經熟悉 Kaggle 網站了,本段可以跳過)

Kaggle 上有兩(liang) 個(ge) 最適合新手的競賽(某種程度上已成為(wei) Kaggle 的「入門教程」):

  • Titanic(預測生存:一種二元分類問題):https://www.kaggle.com/c/titanic

  • 房價(jia) (預測價(jia) 格:回歸問題):https://www.kaggle.com/c/house-prices-advanced-regression-techniques

我強烈建議你兩(liang) 項都嚐試一下,本文主要介紹後者。不過,其中需要的知識大部分是通用的,所以你完全可以看完本文,然後嚐試其他 Kaggle 競賽或者數據科學問題,所以選擇挑戰其他競賽也沒有問題!

在每個(ge) 競賽的「Overview」(概覽)選項卡上,你可以看到關(guan) 於(yu) 比賽及其數據集的一些信息、提交有效結果的評估標準(每個(ge) 競賽都略有不同),以及該競賽的 FAQ。

在「Data」(數據)選項卡上,你可以看到數據的簡要說明。我們(men) 需要的是這三個(ge) 文件:train.csv、test.csv 和 data_description.txt(這是至關(guan) 重要的,因為(wei) 其中包含數據的詳細描述),請將它們(men) 放在你可以快速訪問的文件夾裏。

「Discussions」(討論)選項卡就像競賽的專(zhuan) 屬論壇——不過不要低估它!在流行的競賽中,這些討論中經常包含非常有價(jia) 值的信息,因為(wei) 競賽條款有時會(hui) 要求參與(yu) 者必須在討論版上公開他們(men) 所使用的任何信息。例如,數據泄露是很難避免和處理的,偶爾也會(hui) 發生在競賽中。一方麵,充分利用數據才能得到更高的分數贏得競賽;但另一方麵,結合了數據泄露的模型通常對於(yu) 實踐來說是無用的,所以也不被競賽支持——因為(wei) 它們(men) 使用了「非法」信息。勤奮的參與(yu) 者經常會(hui) 在討論版上分享數據泄露以幫助競賽環境變得更好。此外,Kaggle 的成員也會(hui) 經常在其上分享一些信息,努力維護這個(ge) 社區。在排行榜上名列前茅的參與(yu) 者有時也會(hui) 在其中分享自己的成功經驗(通常會(hui) 在競賽結束前後)。

「Kernel」選項卡基本上是「討論」版塊的應用、代碼版,我認為(wei) 這是對於(yu) 初學者而言最重要的一個(ge) 版塊。任何人都可以在其中分享自己的腳本或筆記,鏈接任何數據集與(yu) 競賽,形式可以是文檔、注釋、可視化和輸出,每個(ge) 人都可以觀看、投票、複製這些內(nei) 容,甚至也可以在瀏覽器上直接運行它們(men) !我剛才提到的兩(liang) 個(ge) 競賽(Titanic、房價(jia) 競賽)都形成了有趣、漂亮、成功的 Kernel,強烈推薦進行過自己的嚐試之後瀏覽這個(ge) 版塊。Kaggle 正在不斷提升 Kernel 的功能,現在甚至有一個(ge) 「僅(jin) 限 Kernel」、獎金為(wei) 10 萬(wan) 美元的競賽。不過,Kernel 中的討論往往是硬核的,缺乏有關(guan) 概念的解釋,或者說預先認為(wei) 你已具備相關(guan) 知識,所以有時了解起來會(hui) 有些許困難。

建立自己的環境

我強烈推薦使用 Python3.6 在 Jupyter Notebook 環境中處理任何數據科學相關(guan) 的工作(其中最流行的發行版稱為(wei) 「Anaconda」,包括 Python、Jupyter Notebook 和很多有用的庫)。然後你就可以通過在終端(或者 Anaconda GUI)輸入 Jupyter Notebook 隨時啟動該環境。除此之外,本文展示的內(nei) 容也可以在 Kaggle 網站上的私人 Kernel 上完成(完全在瀏覽器上工作),這和 Jupyter Notebook 是等價(jia) 的。

在開始之前,先介紹使用 Jupyter Notebook 的幾個(ge) 基本要點:

  • 你可以輸入任意的方法名,然後按 Tab 鍵查看所有可能選項;

  • 類似地,選擇任意方法,按 Shift-Tab 鍵幾次可以在你的 notebook 中打開它的相關(guan) 文檔;

  • 在任意語句之前輸入%time 並執行該 cell,可以輸出所需執行時間;

  • 類似地,在任意語句之前輸入%prun 並執行該 cell,可以令其在 Python 的代碼分析器中運行,並輸出結果。

可以在這裏查看更多有用的命令:https://ipython.readthedocs.io/en/stable/interactive/magics.html

預測房價(jia) 競賽指南

目標概覽

這是一個(ge) 監督學習(xi) 問題,意味著訓練集中包含一係列的觀察數據(行)和相關(guan) 的多種信息(列)。其中一列是我們(men) 感興(xing) 趣並能夠預測的信息,通常稱其為(wei) 目標變量或者因變量,在分類問題中稱為(wei) 標簽、類。在我們(men) 的案例中,目標變量是房價(jia) 。其它的列通常稱為(wei) 獨立變量或特征。我們(men) 還有一個(ge) 測試集,也包含一係列的觀察數據,其中的列與(yu) 訓練集相同,除了目標變量,因為(wei) 我們(men) 的目標就是預測目標變量的值。因此,完美情況下,我們(men) 要建立一個(ge) 模型,該模型可以學習(xi) 訓練集中因變量和獨立變量之間的關(guan) 係,然後使用學習(xi) 到的知識在測試集中盡可能準確地預測因變量(目標變量)的值。由於(yu) 目標變量(房價(jia) )是連續的,可以取任意的值,因此這個(ge) 問題屬於(yu) 回歸問題。

加載和檢查數據

現在我們(men) 已經成功啟動了 Jupyter Notebook,首先要做的事情就是加載數據到 Pandas DataFrame 中。Pandas 可以處理 Python 中所有數據分析相關(guan) 的工作,是很強大和流行的庫,DataFrame 是它用於(yu) 保存數據的對象名稱。

從(cong) 零開始,教初學者如何征戰Kaggle競賽

按 Shift-Tab 幾次,打開文檔。

最後一行使用了 Python 3.6 的字符串格式將從(cong) Kaggle 下載的 CSV 文件(『comma-separated-values』,一種常用格式,可使用任何標準軟件打開,例如 Excel)加載到 Pandas DataFrame 中。我們(men) 之後將頻繁使用 read_csv,因此建議先瀏覽它的文檔(這是一個(ge) 好習(xi) 慣)。加載數據並查看 DataFrame,可以發現數據集中的第一列是 Id,代表數據集中該行的索引,而不是真實觀察值。因此,我修改了代碼,加上 index_col=『Id』作為(wei) 參數,從(cong) 而在加載數據到 DataFrame 的時候,確保 Pandas 將其作為(wei) 索引而不是列,並在它之前添加一個(ge) 新的索引列。

現在,我們(men) 來看看訓練集的樣子。

從(cong) 零開始,教初學者如何征戰Kaggle競賽

訓練集的數據結構

訓練集總共有 80 列(除 Id 以外),其中 79 列是獨立變量,1 列是因變量。因此,測試集應該隻有 79 列(獨立變量)。大多數的數字和字符串都沒有什麽(me) 意義(yi) ,其中 Alley 列甚至全都是『NaN』,即值的丟(diu) 失。別擔心,我們(men) 之後會(hui) 處理這個(ge) 問題。下一步是考慮需要使用的模型。我們(men) 先討論一下決(jue) 策樹(有時在應用到回歸問題的時候稱為(wei) 回歸樹)。

如何構建我們(men) 的模型

決(jue) 策樹介紹

其基本思想是很簡單的,當學習(xi) (擬合)訓練數據的時候,回歸樹搜索所有獨立變量和每個(ge) 獨立變量的所有值,以尋找能將數據最佳地分割為(wei) 兩(liang) 組的變量和值(從(cong) 數學角度來說,樹總是選擇能最小化兩(liang) 個(ge) 節點的加權平均方差的分割),然後計算分數(最好是選定指標上的分數),以及每個(ge) 組因變量的平均值。接著回歸樹遞歸地重複該過程,直到無法進一步分割(除非設置了具體(ti) 的 max_depth,如下圖所示)。樹最後一級的每個(ge) 節點都被稱為(wei) 『葉』,每一個(ge) 都和因變量(在該葉相關(guan) 的所有觀察數據)的平均值相關(guan) 。

旁注:這是一個(ge) 『貪婪』算法的很好示例,在每一次分割中,算法檢查了所有選項,然後選擇了在該點的最佳選項,以期望最終得到全局最佳結果。當樹擬合了訓練數據之後,使用任何觀察數據預測因變量的值時,隻需要遍曆樹,直到抵達一個(ge) 葉節點。

從(cong) 零開始,教初學者如何征戰Kaggle競賽

我們(men) 數據集的可視化示例,其中 max_depth 設為(wei) 3。

在樹的每個(ge) 節點,第一個(ge) 元素是節點的分割規則(獨立變量及其變量值),第二個(ge) 元素是在該節點的所有觀察數據的均方差(MSE),第三個(ge) 元素是該節點的觀察數據的數量(samples),即這一組的規模。最後一個(ge) 元素 value 是目標變量(房價(jia) )的自然對數。該過程和貪婪算法類似,在每個(ge) 節點局部地進行最佳分割,確實可以隨著樹的擴展減少均方差的值,並且每個(ge) 葉節點都有一個(ge) 相關(guan) 的「SalePrice」值。

偏差-方差權衡

我們(men) 回憶一下監督學習(xi) 的目標。一方麵,我們(men) 希望模型可以通過擬合訓練數據捕捉獨立變量和因變量的關(guan) 係,從(cong) 而使其可以做出準確的預測。然而,模型還需要對(未見過的)測試數據進行預測。因此,我們(men) 還希望模型捕捉變量之間的普遍關(guan) 係,從(cong) 而可以進行泛化。該過程稱為(wei) 『偏差-方差權衡』。

從(cong) 零開始,教初學者如何征戰Kaggle競賽

如果模型沒有充分擬合訓練數據,它將會(hui) 有高偏差(通常稱為(wei) 欠擬合),因此它的訓練誤差較大。然而,如果模型過於(yu) 擬合訓練數據,它會(hui) 捕捉到變量之間的特殊關(guan) 係(偶然的),導致高方差(通常稱為(wei) 過擬合),因此它的測試誤差較大。所以,我們(men) 需要在偏差和方差之間進行權衡。

決(jue) 策樹過擬合

假定我們(men) 將一個(ge) 回歸樹擬合到訓練數據中。這個(ge) 樹將是什麽(me) 結構?實際上,它將持續分割直到每個(ge) 葉節點隻有一個(ge) 觀察數據(無法再繼續分離)。換種說法,回歸樹將為(wei) 訓練集的每一個(ge) 觀察數據建立一個(ge) 獨特路徑,並根據觀察數據在路徑末端的葉節點上給出因變量的值。

如果將訓練集中因變量的值刪除,並用訓練過的樹預測因變量的值,結果如何?可以猜到,它將表現得很完美,達到基本 100% 的準確率和 0 均方差。因為(wei) 它已經學習(xi) 了訓練集中每個(ge) 觀察數據的相關(guan) 因變量值。

然而,如果我打算讓樹預測未見過的觀察數據的因變量值,它將表現得很糟糕,因為(wei) 任何未見過的觀察數據都會(hui) 在原來的樹構建一個(ge) 獨特的葉節點。這正是一個(ge) 過擬合的例子。可以通過調整樹的參數減少過擬合,例如,限製樹的 max_depth,但實際上還有更好的方法。

解決(jue) 方案:隨機森林

在機器學習(xi) 中,我們(men) 通常會(hui) 設計「元學習(xi) 」以結合小模型的多個(ge) 預測而生成更好的最終預測,這種方法一般可稱為(wei) 集成學習(xi) 。特別的,當我們(men) 結合一些決(jue) 策樹為(wei) 單個(ge) 集成模型,我們(men) 可以將其稱之為(wei) 「Bootstrap Aggregating」或簡單地稱之為(wei) 「Bagging」。通過這種方法構建的「元模型」是一種較為(wei) 通用的解決(jue) 方案,因此隨機森林可以適用於(yu) 廣泛的任務。

隨機森林簡單而高效,當我們(men) 用這種方法擬合一個(ge) 數據集時,就會(hui) 像上文所述的那樣構建許多決(jue) 策樹,隻不過每個(ge) 決(jue) 策樹是在數據的隨機子集中構建,且在每一次分割中隻考慮獨立變量「特征」的隨機子集。然後為(wei) 了生成新的觀察值,隨機森林會(hui) 簡單地平均所有樹的預測,並將其作為(wei) 最終的預測返回。

現在我們(men) 所做的的就是構建許多弱分類器或弱決(jue) 策樹,然後取它們(men) 的平均值,為(wei) 什麽(me) 要這樣做呢?

簡單的回答就是它們(men) 確實工作地非常好,如果讀者對隨機森林的統計解釋感興(xing) 趣的話,可以閱讀更多的技術細節。但我不擅長於(yu) 統計,但我會(hui) 盡可能地給出一個(ge) 基本的解釋:bootstrap 采樣和特征子集可以使不同的決(jue) 策樹盡可能地去相關(guan) (即使它們(men) 仍然基於(yu) 相同的數據集和特征集),這種去相關(guan) 能允許每一棵樹在數據中發現一些不同的關(guan) 係。這也就使它們(men) 的均方差要比任何單顆樹都少的多,因此減少過擬合後它們(men) 能在總體(ti) 上獲得更好的預測和泛化結果。

簡單來說,對於(yu) 未見的觀察結果,每個(ge) 決(jue) 策樹預測該觀察結果結束時所處葉節點的因變量值,即特定樹空間中最類似的訓練集觀察結果。每棵樹都是在不同的數據上構建的不同樹,因此每棵樹用不同的方式定義(yi) 相似性,預測不同的值。因此對於(yu) 給定未見觀察結果,所有樹的平均預測基本上就是訓練集中與(yu) 之類似的觀察結果的值的平均值。

此特性的影響之一是:盡管隨機森林在測試集與(yu) 訓練集相似度較高時(值屬於(yu) 同樣的範圍)非常擅長預測,但當測試集與(yu) 訓練集存在根本區別時(不同範圍的值),隨機森林的預測性能很差,比如時序問題(訓練集和測試集不屬於(yu) 同樣的時間段)。

不過我們(men) 的案例中測試集和訓練集具備同樣範圍的值,因此這對我們(men) 沒有太大影響。

回到比賽

預處理數據

我們(men) 在讓隨機森林運行起來之前還有一件事要做:隨機森林雖然理論上可以應對分類特征(非數據形式:字符串)和數據缺失,scikit-learn 實現卻並不支持這兩(liang) 種情況。所以我們(men) 需要使用 pd.interpolate() 來填充缺失的值,然後使用 pd.get_dummies() 的『One-Hot Encoding』來將分類特征轉換為(wei) 數字特征。這個(ge) 方法非常簡單,讓我們(men) 假設一個(ge) 分類變量有 n 個(ge) 可能值。該列被分為(wei) n 個(ge) 列,每一列對應一個(ge) 原始值(相當於(yu) 對每個(ge) 原始值的『is_value?』)。每個(ge) 觀察值(以前有一個(ge) 分類變量的字符串值),現在在舊字符串值對應的列上有一個(ge) 1,而其他所有列上為(wei) 0。

我們(men) 現在準備構建一個(ge) 模型,使用數據進行訓練,並用它來預測測試集,然後將結果提交到 Kaggle 上。

整合結果並提交

這就是我們(men) 的模型提交 Kaggle 所需的所有代碼——大約 20 行!我們(men) 運行這些代碼,隨後繼續向 Kaggle 提交結果——得分為(wei) 0.14978,目前排行約為(wei) 63%。對於(yu) 五分鍾的代碼編寫(xie) 來說,結果不錯!在這裏我們(men) 可以看到隨機森林的力量。

  1. import pandas as pd
  2. from sklearn.ensemble import RandomForestRegressor
  3. PATH = "Oren/Kaggle/Housing Prices/" #where you put the files
  4. df_train = pd.read_csv(f'{PATH}train.csv', index_col='Id')
  5. df_test = pd.read_csv(f'{PATH}test.csv', index_col='Id')
  6. target = df_train['SalePrice'] #target variable
  7. df_train = df_train.drop('SalePrice', axis=1)
  8. df_train['training_set'] = True
  9. df_test['training_set'] = False
  10. df_full = pd.concat([df_train, df_test])
  11. df_full = df_full.interpolate()
  12. df_full = pd.get_dummies(df_full)
  13. df_train = df_full[df_full['training_set']==True]
  14. df_train = df_train.drop('training_set', axis=1)
  15. df_test = df_full[df_full['training_set']==False]
  16. df_test = df_test.drop('training_set', axis=1)
  17. rf = RandomForestRegressor(n_estimators=100, n_jobs=-1)
  18. rf.fit(df_train, target)
  19. preds = rf.predict(df_test)
  20. my_submission = pd.DataFrame({'Id': df_test.index, 'SalePrice': preds})
  21. my_submission.to_csv(f'{PATH}submission.csv', index=False)

說明

在將訓練集和測試集分別加載進 DataFrame 之後,我保存了目標變量,並在 DataFrame 中刪除它(因為(wei) 我隻想保留 DataFrame 中的獨立變量和特征)。隨後,我在訓練集和測試集中添加了一個(ge) 新的臨(lin) 時列('training_set'),以便我們(men) 可以將它們(men) 連接在一起(將它們(men) 放在同一個(ge) DataFrame 中),然後再將它們(men) 分開。我們(men) 繼續整合它們(men) ,填充缺失的數值,並通過獨熱編碼(One-Hot Encoding)將分類特征轉換為(wei) 數字特征。

正如之前所述的,隨機森林(以及其他大多數算法)都會(hui) 在訓練集和測試集有差不多數值的情況下工作良好,所以在修改內(nei) 容的時候我希望對兩(liang) 個(ge) 數據集進行同樣的修改。否則,interpolate 可能會(hui) 在訓練集和測試集上填入不同的數值,而 get_dummies 可能會(hui) 以兩(liang) 種不同的方式對相同的分類特征進行編碼,從(cong) 而導致性能下降。隨後我在將其分開,去掉臨(lin) 時列,構建一個(ge) 有 100 個(ge) 樹的隨機森林(通常,樹越多結果越好,但這也意味著訓練時間的增加),使用計算機的所有 CPU 核心(n_jobs=-1),使用訓練集進行擬合,用擬合的隨機森林來預測測試集的目標變量,把結果和它們(men) 各自的 Id 放在一個(ge) DataFrame 中,並保存到 一個(ge) CSV 文件中。隨後登陸 Kaggle 頁麵提交 CSV 文件,大功告成!

原文地址:https://towardsdatascience.com/machine-learning-zero-to-hero-everything-you-need-in-order-to-compete-on-kaggle-for-the-first-time-18644e701cf1

【競賽報名/項目谘詢+微信:mollywei007】

上一篇

The Avogadro Exam阿伏伽德羅化學競賽介紹

下一篇

CB官方宣布2023年SAT考試新方案

你也可能喜歡

  • 暫無相關文章!

評論已經被關(guan) 閉。

插入圖片
返回頂部