介紹
kaggle是全球最好的一個數據科學競賽平臺,今天講其中一個非常經典的預測比賽,一年前我就參加過這個比賽,當時的代碼也保留了,現在運行的時候有幾處python方法調用的兼容問題,其他都正常跑沒有問題。
站在現在的角度來看這個比賽,感覺非常完整,覆蓋了正常機器學習工作中的流程和問題。其實有很多公司會把它們的機器學習項目放到kaggle上,然後設置金獎,當有團隊做出很好的效果和解決方案,它們就會買過來,可以理解為有了kaggle上的比賽經驗,就和有實際的工作經驗差不多,尤其是可以取到名次的同學,簡歷上直接寫出來,就是加分項。
準備工作
註冊賬號並報名比賽,地址:https://www.kaggle.com/c/titanic
下載訓練集和測試集數據,地址:https://www.kaggle.com/c/titanic/data
安裝jupyter notebook,地址:http://codingpy.com/article/getting-started-with-jupyter-notebook-part-1/
-
具備pandas,numpy和matplotlib的基礎
比賽描述
背景就是那個感人的愛情故事,Jack和Rose本來能夠幸福的一起在美國生活,但是由於輪船的管理層傲慢和大意,在晚上可見度不高的情況下還要全速前進,結果看到冰山的時候來不及躲,還是撞上了。救生艇數量很少,船上的遊客一部分獲救,另一部分遇難。我們要做的就是根據船上一部分乘客的信息來預測一部分乘客是否獲救。
參加比賽的步驟:
根據訓練集數據和測試集數據生成自己的預測模型
按照預測模型來預測出892到1309條數據是否獲救
按照比賽規定的格式生成csv文件,並上傳到kaggle上,然後會反饋預測的準確率
流程
結合吳恩達老師講的機器學習思路來解決這個問題:(課程地址:https://www.coursera.org/learn/machine-learning)
不要想著一下子就生成一個完美的模型,首先根據問題分析出一個基礎模型,Base Model
分析Base Model的的狀態,是擬合還是過擬合
分析Base Model中使用的特徵效果如何,然後進行特徵選擇
收集預測錯誤的case,並分析這些Bad case產生的原因
生成Base Model
首先我們來分析一下訓練集的數據,看看都有哪些字段:
執行下面兩行代碼
data_train = pd.read_csv("Train.csv")
data_train.head()
表中的字段各代表的意思是:
PassengerId : 乘客ID
Pclass : 乘客等級 1,2,3等艙位
Name : 乘客姓名
Sex : 性別
Age :年齡
SibSp : 堂兄弟/妹個數
Parch : 父母與小孩個數
Ticket : 船票信息
Fare : 票價
Cabin : 客艙
Embarked : 登船港口
相信看過電影的同學都記得最後上救生艇的場景:
1."Women and children first"
2.那個有錢的男的最後獲救了
3.很多3等艙位的人被堵在下面不讓上
根據這些可以得出,艙位等級,性別和年齡,是否有錢。這些特徵可能會影響是否獲救的概率。下面我們來通過圖表來分析一下訓練集:
艙位的等級和對應的獲救情況,執行代碼
fig = plt.figure()
fig.set(alpha=0.2)
Survived_n = data_train.Pclass[data_train.Survived == 0].value_counts()
Survived_y = data_train.Pclass[data_train.Survived == 1].value_counts()
df=pd.DataFrame({u'Survived':Survived_y, u'not Survived':Survived_n})
df.plot(kind='bar', stacked=True)
plt.xlabel(u"class")
plt.ylabel(u"count")
plt.show()
好吧,果然是越有錢,獲救的概率越大,不評論了。轉換到特徵上就是Pclass這個字段等於1的時候,獲救的概率大。
下面再來看一下性別影響的比例,代碼如下:
Survived_m = data_train.Survived[data_train.Sex == 'male'].value_counts()
Survived_f = data_train.Survived[data_train.Sex == 'female'].value_counts()
df=pd.DataFrame({u'man':Survived_m, u'women':Survived_f})
df.plot(kind='bar', stacked=True)
plt.xlabel(u"sex")
plt.ylabel(u"count")
plt.show()
沒錯,女性獲救的比例高,Sex這個字段是female的時候,獲救概率高。
好的,我們用LR(邏輯迴歸)來建模,這時候還需要做一個處理,就是 one-hot encoding (獨熱向量編碼) ,因為邏輯迴歸建模時,需要輸入的特徵都是數值型特徵
以Sex為例,原本一個屬性維度,因為其取值可以是[‘male’,’female’],而將其平展開為’Sex_male’,’Sex_female’兩個屬性
原本Sex取值為male的,在此處的”Cabin_male”下取值為1,在”Cabin_female”下取值為0
原本Sex取值為female的,在此處的”Cabin_female”下取值為0,在”Cabin_male”下取值為1
我們使用pandas的”get_dummies”來完成這個工作,並拼接在原來的”data_train”之上,代碼如下:
dummies_Cabin = pd.get_dummies(data_train['Cabin'], prefix= 'Cabin')
dummies_Embarked = pd.get_dummies(data_train['Embarked'], prefix= 'Embarked')
dummies_Sex = pd.get_dummies(data_train['Sex'], prefix= 'Sex')
dummies_Pclass = pd.get_dummies(data_train['Pclass'], prefix= 'Pclass')
df = pd.concat([data_train, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
df.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)
這樣我們得到的屬性都轉為0,1的值了
建模
代碼如下:
train_df = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
train_np = train_df.as_matrix()
y = train_np[:, 0]
X = train_np[:, 1:]
clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
clf.fit(X, y)
clf
用正則取出我們要的屬性值 ,其中y即Survival結果,x即特徵屬性值。
處理test的數據
把剛才做過的處理,同樣的複製一份到test.csv上,代碼如下:
data_test = pd.read_csv("test.csv")
data_test.loc[ (data_test.Fare.isnull()), 'Fare' ] = 0
tmp_df = data_test[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]
null_age = tmp_df[data_test.Age.isnull()].as_matrix()
X = null_age[:, 1:]
predictedAges = rfr.predict(X)
data_test.loc[ (data_test.Age.isnull()), 'Age' ] = predictedAges
data_test = set_Cabin_type(data_test)
dummies_Cabin = pd.get_dummies(data_test['Cabin'], prefix= 'Cabin')
dummies_Embarked = pd.get_dummies(data_test['Embarked'], prefix= 'Embarked')
dummies_Sex = pd.get_dummies(data_test['Sex'], prefix= 'Sex')
dummies_Pclass = pd.get_dummies(data_test['Pclass'], prefix= 'Pclass')
df_test = pd.concat([data_test, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
df_test.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)
df_test['Age_scaled'] = scaler.fit_transform(df_test['Age'].reshape(-1, 1), age_scale_param)
df_test['Fare_scaled'] = scaler.fit_transform(df_test['Fare'].reshape(-1, 1), fare_scale_param)
生成結果
最後一步,把測試集的數據放到LR的模型中去預測,並且保存到csv文件中,代碼如下:
test = df_test.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*|Name')
predictions = clf.predict(test)
result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions.astype(np.int32)})
result.to_csv("logistic_regression_predictions.csv", index=False)
上傳結果
打開kaggle中的titanic的頁面,找到submit predictions的按鈕,點擊上傳剛才導出的csv文件,然後等待處理後,結果如下:
排名是7000多名,準確率76.555% 當然這只是Base Model,初步的一個處理,所以準確率不高,接下來我們需要做的就是調優。
總結:
完成了Base Model的建立,抽取了幾個重要特徵了,瞭解為什麼要用one-hot encoding。
熟悉了參加kaggle比賽的流程,之後建議多拿kaggle裡的比賽來練習。
閱讀更多 5分鐘機器學習 的文章