項目 0: 預測泰坦尼克號乘客生還率

機器學習工程師納米學位

機器學習基礎

項目 0: 預測泰坦尼克號乘客生還率

1912年,泰坦尼克號在第一次航行中就與冰山相撞沉沒,導致了大部分乘客和船員身亡。在這個入門項目中,我們將探索部分泰坦尼克號旅客名單,來確定哪些特征可以最好地預測一個人是否會生還。為了完成這個項目,你將需要實現幾個基于條件的預測并回答下面的問題。我們將根據代碼的完成度和對問題的解答來對你提交的項目的進行評估。

提示:這樣的文字將會指導你如何使用 iPython Notebook 來完成項目。

點擊這里查看本文件的英文版本。

了解數據

當我們開始處理泰坦尼克號乘客數據時,會先導入我們需要的功能模塊以及將數據加載到 pandas DataFrame。運行下面區域中的代碼加載數據,并使用 .head()函數顯示前幾項乘客數據。

提示:你可以通過單擊代碼區域,然后使用鍵盤快捷鍵 Shift+EnterShift+ Return 來運行代碼。或者在選擇代碼后使用播放(run cell)按鈕執行代碼。像這樣的 MarkDown 文本可以通過雙擊編輯,并使用這些相同的快捷鍵保存。Markdown 允許你編寫易讀的純文本并且可以轉換為 HTML。

# 檢查你的Python版本
from sys import version_info
if version_info.major != 2 and version_info.minor != 7:
    raise Exception('請使用Python 2.7來完成此項目')
import numpy as np
import pandas as pd

# 數據可視化代碼
from titanic_visualizations import survival_stats
from IPython.display import display
%matplotlib inline

# 加載數據集
in_file = 'titanic_data.csv'
full_data = pd.read_csv(in_file)

# 顯示數據列表中的前幾項乘客數據
display(full_data.head())
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S

從泰坦尼克號的數據樣本中,我們可以看到船上每位旅客的特征

  • Survived:是否存活(0代表否,1代表是)
  • Pclass:社會階級(1代表上層階級,2代表中層階級,3代表底層階級)
  • Name:船上乘客的名字
  • Sex:船上乘客的性別
  • Age:船上乘客的年齡(可能存在 NaN
  • SibSp:乘客在船上的兄弟姐妹和配偶的數量
  • Parch:乘客在船上的父母以及小孩的數量
  • Ticket:乘客船票的編號
  • Fare:乘客為船票支付的費用
  • Cabin:乘客所在船艙的編號(可能存在 NaN
  • Embarked:乘客上船的港口(C 代表從 Cherbourg 登船,Q 代表從 Queenstown 登船,S 代表從 Southampton 登船)

因為我們感興趣的是每個乘客或船員是否在事故中活了下來。可以將 Survived 這一特征從這個數據集移除,并且用一個單獨的變量 outcomes 來存儲。它也做為我們要預測的目標。

運行該代碼,從數據集中移除 Survived 這個特征,并將它存儲在變量 outcomes 中。

# 從數據集中移除 'Survived' 這個特征,并將它存儲在一個新的變量中。
outcomes = full_data['Survived']
data = full_data.drop('Survived', axis = 1)

# 顯示已移除 'Survived' 特征的數據集
display(data.head())
PassengerId Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S

這個例子展示了如何將泰坦尼克號的 Survived 數據從 DataFrame 移除。注意到 data(乘客數據)和 outcomes (是否存活)現在已經匹配好。這意味著對于任何乘客的 data.loc[i] 都有對應的存活的結果 outcome[i]

計算準確率

為了驗證我們預測的結果,我們需要一個標準來給我們的預測打分。因為我們最感興趣的是我們預測的準確率,既正確預測乘客存活的比例。運行下面的代碼來創建我們的 accuracy_score 函數以對前五名乘客的預測來做測試。

思考題:在前五個乘客中,如果我們預測他們全部都存活,你覺得我們預測的準確率是多少?

In [5]:

def accuracy_score(truth, pred):
    """ 返回 pred 相對于 truth 的準確率 """
    
    # 確保預測的數量與結果的數量一致
    if len(truth) == len(pred): 
        
        # 計算預測準確率(百分比)
        return "Predictions have an accuracy of {:.2f}%.".format((truth == pred).mean()*100)
    
    else:
        return "Number of predictions does not match number of outcomes!"
    
# 測試 'accuracy_score' 函數
predictions = pd.Series(np.ones(5, dtype = int)) #五個預測全部為1,既存活
print accuracy_score(outcomes[:5], predictions)

Predictions have an accuracy of 60.00%.

提示:如果你保存 iPython Notebook,代碼運行的輸出也將被保存。但是,一旦你重新打開項目,你的工作區將會被重置。請確保每次都從上次離開的地方運行代碼來重新生成變量和函數。

最簡單的預測

如果我們要預測泰坦尼克號上的乘客是否存活,但是我們又對他們一無所知,那么最好的預測就是船上的人無一幸免。這是因為,我們可以假定當船沉沒的時候大多數乘客都遇難了。下面的 predictions_0 函數就預測船上的乘客全部遇難。

def predictions_0(data):
    """ 不考慮任何特征,預測所有人都無法生還 """

    predictions = []
    for _, passenger in data.iterrows():
        
        # 預測 'passenger' 的生還率
        predictions.append(0)
    
    # 返回預測結果
    return pd.Series(predictions)

# 進行預測
predictions = predictions_0(data)

問題1:對比真實的泰坦尼克號的數據,如果我們做一個所有乘客都沒有存活的預測,這個預測的準確率能達到多少?

回答61.62%

提示:運行下面的代碼來查看預測的準確率。

print accuracy_score(outcomes, predictions)

Predictions have an accuracy of 61.62%.

考慮一個特征進行預測

我們可以使用 survival_stats 函數來看看 Sex 這一特征對乘客的存活率有多大影響。這個函數定義在名為 titanic_visualizations.py 的 Python 腳本文件中,我們的項目提供了這個文件。傳遞給函數的前兩個參數分別是泰坦尼克號的乘客數據和乘客的 生還結果。第三個參數表明我們會依據哪個特征來繪制圖形。

運行下面的代碼繪制出依據乘客性別計算存活率的柱形圖。

survival_stats(data, outcomes, 'Sex')
image.png

觀察泰坦尼克號上乘客存活的數據統計,我們可以發現大部分男性乘客在船沉沒的時候都遇難了。相反的,大部分女性乘客都在事故中生還。讓我們以此改進先前的預測:如果乘客是男性,那么我們就預測他們遇難;如果乘客是女性,那么我們預測他們在事故中活了下來。

將下面的代碼補充完整,讓函數可以進行正確預測。

提示:您可以用訪問 dictionary(字典)的方法來訪問船上乘客的每個特征對應的值。例如, passenger['Sex'] 返回乘客的性別。

def predictions_1(data):
    """ 只考慮一個特征,如果是女性則生還 """
    
    predictions = []
    for _, passenger in data.iterrows():

        # TODO 1
        # 移除下方的 'pass' 聲明
        # 輸入你自己的預測條件
        if passenger['Sex'] == 'male':
            predictions.append(0)
        else:
            predictions.append(1)
    
    # 返回預測結果
    return pd.Series(predictions)

# 進行預測
predictions = predictions_1(data)

問題2:當我們預測船上女性乘客全部存活,而剩下的人全部遇難,那么我們預測的準確率會達到多少?

回答: 78.68%

提示:你需要在下面添加一個代碼區域,實現代碼并運行來計算準確率。

print accuracy_score(outcomes, predictions)

Predictions have an accuracy of 78.68%.

考慮兩個特征進行預測

僅僅使用乘客性別(Sex)這一特征,我們預測的準確性就有了明顯的提高。現在再看一下使用額外的特征能否更進一步提升我們的預測準確度。例如,綜合考慮所有在泰坦尼克號上的男性乘客:我們是否找到這些乘客中的一個子集,他們的存活概率較高。讓我們再次使用 survival_stats 函數來看看每位男性乘客的年齡(Age)。這一次,我們將使用第四個參數來限定柱形圖中只有男性乘客。

運行下面這段代碼,把男性基于年齡的生存結果繪制出來。

survival_stats(data, outcomes, 'Age', ["Sex == 'male'"])
image.png

仔細觀察泰坦尼克號存活的數據統計,在船沉沒的時候,大部分小于10歲的男孩都活著,而大多數10歲以上的男性都隨著船的沉沒而遇難。讓我們繼續在先前預測的基礎上構建:如果乘客是女性,那么我們就預測她們全部存活;如果乘客是男性并且小于10歲,我們也會預測他們全部存活;所有其它我們就預測他們都沒有幸存。

將下面缺失的代碼補充完整,讓我們的函數可以實現預測。
提示: 您可以用之前 predictions_1 的代碼作為開始來修改代碼,實現新的預測函數。

def predictions_2(data):
    """ 考慮兩個特征: 
            - 如果是女性則生還
            - 如果是男性并且小于10歲則生還 """
    
    predictions = []
    for _, passenger in data.iterrows():
        
        # TODO 2
        # 移除下方的 'pass' 聲明
        # 輸入你自己的預測條件
        
        if passenger['Sex'] == 'female':
            predictions.append(1)
        elif passenger['Age'] < 10:
            predictions.append(1)
        else:
            predictions.append(0)
            
## 用這段代碼準確率下降了,(原因是數據中有字段值缺失)       
#         if passenger['Sex'] == 'male':
#             if passenger['Age'] >= 10:
#                 predictions.append(0)
#             else:
#                 predictions.append(1)
#         else:
#             predictions.append(1)
    
    # 返回預測結果
    return pd.Series(predictions)

# 進行預測
predictions = predictions_2(data)

問題3:當預測所有女性以及小于10歲的男性都存活的時候,預測的準確率會達到多少?

回答: 79.35%

提示:你需要在下面添加一個代碼區域,實現代碼并運行來計算準確率。

print accuracy_score(outcomes, predictions)

Predictions have an accuracy of 79.35%.

你自己的預測模型

添加年齡(Age)特征與性別(Sex)的結合比單獨使用性別(Sex)也提高了不少準確度。現在該你來做預測了:找到一系列的特征和條件來對數據進行劃分,使得預測結果提高到80%以上。這可能需要多個特性和多個層次的條件語句才會成功。你可以在不同的條件下多次使用相同的特征。PclassSexAgeSibSpParch 是建議嘗試使用的特征。

使用 survival_stats 函數來觀測泰坦尼克號上乘客存活的數據統計。
提示: 要使用多個過濾條件,把每一個條件放在一個列表里作為最后一個參數傳遞進去。例如: ["Sex == 'male'", "Age < 18"]

survival_stats(data, outcomes, "Pclass")
image.png
survival_stats(data, outcomes, "Pclass",["Sex == 'female'"] )
image.png
survival_stats(data, outcomes, 'Parch', ["Pclass == 3","Sex == 'female'",])
image.png
survival_stats(data, outcomes, "SibSp",["Pclass == 3","Sex == 'female'","Parch > 0"] )
image.png
survival_stats(data, outcomes, "SibSp",["Pclass == 3","Sex == 'female'","Parch > 0","Parch > 0"] )
image.png
survival_stats(data, outcomes, "Parch",["Pclass == 1","Sex == 'male'","Age >= 10"] )
image.png

當查看和研究了圖形化的泰坦尼克號上乘客的數據統計后,請補全下面這段代碼中缺失的部分,使得函數可以返回你的預測。
在到達最終的預測模型前請確保記錄你嘗試過的各種特征和條件。
提示: 您可以用之前 predictions_2 的代碼作為開始來修改代碼,實現新的預測函數。

def predictions_3(data):
    """ 考慮多個特征,準確率至少達到80% """
    
    predictions = []
    for _, passenger in data.iterrows():
        
        # TODO 3
        # 移除下方的 'pass' 聲明
        # 輸入你自己的預測條件
        if passenger['Sex'] == 'female':
            
            if passenger['Pclass'] == 3 and passenger['Parch'] > 0 and passenger['SibSp'] > 0:
                predictions.append(0)
            else:
                predictions.append(1)   
                
        elif passenger['Age'] < 10:
            predictions.append(1)
        else:
            predictions.append(0)
    
    # 返回預測結果
    return pd.Series(predictions)

# 進行預測
predictions = predictions_3(data)

問題4:請描述你實現80%準確度的預測模型所經歷的步驟。您觀察過哪些特征?某些特性是否比其他特征更有幫助?你用了什么條件來預測生還結果?你最終的預測的準確率是多少?

回答通過前面的Sex和Age特征分析大致了解了分析過程和影響結果,后來單獨觀察過特征有Pclass、Parch、SibSp,發現Pclass==3時死亡比例相對很高,又由于之前在決策樹根分支下將female全部假設存活,所以想按照Pclass特征將female中的死亡的區分出來,發現Pclass==3時female死亡和存活的比例相同,然后再想能否在該條件下通過其他特征進行區分,試了Age發現很難區分,然后分別試了Parch和SibSp,發現Parch>0或SibSp>0時,female死亡率均>50%,由此,可以將female在Pclass==3條件下,Parch>0或SibSp>0的全部假設為死亡,這樣會提供死亡的預測準確性。通過實驗發現,Parch>0或SibSp>0時均提高準確率到81.03%,若兩者同時滿足測準確率又進一步提高,所以最終采用了Parch>0且SibSp>0來將女性低階層的假設為死亡,準確率達到81.14%

提示:你需要在下面添加一個代碼區域,實現代碼并運行來計算準確率。

print accuracy_score(outcomes, predictions)

Predictions have an accuracy of 81.14%.

結論

經過了數次對數據的探索和分類,你創建了一個預測泰坦尼克號乘客存活率的有用的算法。在這個項目中你手動地實現了一個簡單的機器學習模型——決策樹(decision tree)。決策樹每次按照一個特征把數據分割成越來越小的群組(被稱為 nodes)。每次數據的一個子集被分出來,如果分割后新子集之間的相似度比分割前更高(包含近似的標簽),我們的預測也就更加準確。電腦來幫助我們做這件事會比手動做更徹底,更精確。這個鏈接提供了另一個使用決策樹做機器學習入門的例子。

決策樹是許多監督學習算法中的一種。在監督學習中,我們關心的是使用數據的特征并根據數據的結果標簽進行預測或建模。也就是說,每一組數據都有一個真正的結果值,不論是像泰坦尼克號生存數據集一樣的標簽,或者是連續的房價預測。

問題5:想象一個真實世界中應用監督學習的場景,你期望預測的結果是什么?舉出兩個在這個場景中能夠幫助你進行預測的數據集中的特征。

回答: 天氣預報的預測,預測明天是否晴天還是非晴天,特征數據有:今天是否天晴、風力、濕度、氣壓等

注意: 當你寫完了所有5個問題,3個TODO。你就可以把你的 iPython Notebook 導出成 HTML 文件。你可以在菜單欄,這樣導出File -> Download as -> HTML (.html) 把這個 HTML 和這個 iPython notebook 一起做為你的作業提交。


翻譯:毛禮建 | 校譯:黃強 | 審譯:曹晨巍

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容