新手玩Kaggle入門

最近終於把史丹佛的機器學習課程上完了,有了一點概念之後就會想要找一些真實的案例來玩
之前一直想要玩玩Kaggle,但是不知道怎麼入門
看了一些資料之後決定先從成功送出第一次Submission著手吧

在Kaggle送出第一個submission

Kaggle有給新手一個入門用的預測鐵達尼號生存者的問題
https://www.kaggle.com/c/titanic

怎麼解這個問題我這邊先不管,總之我要想辦法先送出一個submission
先關注右邊的選單列

要在Kaggle送出submission除了解問題之外,還有一個重要的地方是這個問題期待的output是什麼格式
Data的連結裡面,除了訓練資料測試資料之外,通常也都會有submission接受的sample或是產生方法
以鐵達尼號這個問題來說,他是用一個genderclassmodel這個程式去產生submission接受的output

研究了一下內容,鐵達尼號這個問題期望的是以test.csv檔案為基礎產生的乘客生存的預測結果的csv檔,範例如下
1代表乘客生存,0則相反

這裡先不用任何分析跟演算法,直接亂數生成一個結果,python範例程式如下
先從網站上把train.csv跟test.csv抓下來,然後做一個my_first_kaggle.py的檔案

my_first_kaggle.py
import numpy as np
import os
import pandas as pd


SCRIPT_PATH = os.path.dirname(os.path.abspath( __file__ ))
test_data = pd.read_csv(SCRIPT_PATH + "/test.csv")
#產生一個長度跟test data一樣的序列,50%的機率是0,50%的機率是1

rand_labels = (np.random.rand(len(test_data['PassengerId'])) > 0.5).astype(np.int32)

results = pd.DataFrame({
    'PassengerId' : test_data['PassengerId'],
    'Survived' : rand_labels
})

results.to_csv(SCRIPT_PATH + "/submission1.csv", index=False)

用一個亂數序列去模擬答案,產生一個結果檔案submission1.csv
結果檔案產生之後從Make a submission連結進去上傳檔案

結果出來啦,6000多名,隨便亂猜的結果表現非常差(理所當然)
雖然效果很差但至少成功送出submission了

嘗試改善performance

能送出submission就是一個開始,接下來就是來真正看看鐵達尼號乘客生存率這個問題試著去改善performance
這部分可以參考kaggle kernels別人的解答
或是參考網站上的攻略https://www.kaggle.com/mrisdal/titanic/exploring-survival-on-the-titanic

雖說敝人不是這方面的專家,就先用自己的方式的看看這個問題
鐵達尼號乘客生存與否預測

  • Output: 乘客生存與否
  • Input: 乘客屬性,姓名,性別,年齡等等

嗯...這是一個二元分類的問題,處理二元分類的問題直覺的想法是考慮logistic
在回頭看看input資料的長相

Variable Name Description
Survived Survived (1) or died (0)
Pclass Passenger’s class
Name Passenger’s name
Sex Passenger’s sex
Age Passenger’s age
SibSp Number of siblings/spouses aboard
Parch Number of parents/children aboard
Ticket Ticket number
Fare Fare
Cabin Cabin
Embarked Port of embarkation

類別特徵占了大多數,其中還有些欄位是有缺值的
這樣看來用logistic似乎沒那麼直覺
而對於這樣類別特徵跟有缺值的特徵當下可以想到的方法就是用決策樹
就來跑個RandomForest(隨機森林樹)吧

先用RandomForest看看哪些特徵是比較重要的
先把測試資料讀進來

import numpy as np
import matplotlib.pyplot as plt
import os
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import LabelEncoder


SCRIPT_PATH = os.path.dirname(os.path.abspath( __file__ ))
dataset = pd.read_csv(SCRIPT_PATH + "/train.csv")

#features = ['Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked']

features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Cabin', 'Embarked']
training_data = dataset[features]
training_label = dataset['Survived']

做適當的特徵轉換,將String type的類別進行Label encoding,並將缺值的部分填0

training_data = training_data.fillna(0)
#training_data['Name'] = LabelEncoder().fit_transform(training_data['Name'])

training_data['Sex'] = LabelEncoder().fit_transform(training_data['Sex'])
#training_data['Ticket'] = LabelEncoder().fit_transform(training_data['Ticket'])

training_data['Cabin'] = LabelEncoder().fit_transform(training_data['Cabin'])
training_data['Embarked'] = LabelEncoder().fit_transform(training_data['Embarked'])

跑個RandomForest看看哪些特徵比較重要
這裡要注意的是我先人為判斷了名字跟票根不重要,所以事先將這兩個特徵抽離

model = RandomForestClassifier()
model.fit(training_data, training_label)

y_pos = np.arange(len(features))
plt.barh(y_pos, model.feature_importances_, align='center', alpha=0.4)
plt.yticks(y_pos, features)
plt.xlabel('features')
plt.title('feature_importances')
plt.show()

結果跑出來後,從圖中主觀的判斷Sex, Age, Fare特徵應該是相對重要的,所以之後的訓練我就選擇使用這前三高的特徵進行訓練
從新建立training dataset之後開始建立預測模型並輸出結果

features = ['Sex', 'Age', 'Fare']
training_data = dataset[features]
training_data = training_data.fillna(0)
training_data['Sex'] = LabelEncoder().fit_transform(training_data['Sex'])
model = RandomForestClassifier()
model.fit(training_data, training_label)

test_data = pd.read_csv(SCRIPT_PATH + "/test.csv")
preidction_data = test_data[features]
preidction_data = preidction_data.fillna(0)
preidction_data['Sex'] = LabelEncoder().fit_transform(preidction_data['Sex'])
result_lables = model.predict(preidction_data)
results = pd.DataFrame({
    'PassengerId' : test_data['PassengerId'],
    'Survived' : result_lables
})

results.to_csv(SCRIPT_PATH + "/submission2.csv", index=False)

順便跑個cross_validation看看

from sklearn.cross_validation import cross_val_score
cv_scores = np.mean(cross_val_score(model, training_data, training_label, scoring='roc_auc', cv=5))
print cv_scores
#output:0.808971923178

這邊要注意一點,我用的sklearn是0.15所以是從sklearn.cross_validation去import cross_val_score
如果是0.18+的話要從sklearn.model_selection去import
建立了模型之後用於model.predict去產生預測結果submission2.csv重新送出submission看看

名次上昇了幾百名,實際命中率上昇了2x%,跟cross validation有點落差,成績沒有說很好,但是有改善總是個好的開始
接下來就能嘗試各種參數來玩啦

2016/12/24

紀錄玩kaggle要注意的事
How to select your final models in a Kaggle competition

comments powered by Disqus