python 分析泰坦尼克號生還率

sixkery發表於2019-03-04

泰坦尼克號資料集,是kaggle(Titanic: Machine Learning from Disaster)上入門機器學習(ML)的一個好的可選資料集,當然,也是不錯的練習資料分析的資料集。對 python ,在資料分析方面,作為一柄利器,涵蓋了「資料獲取→資料處理→資料分析→資料視覺化」這個流程中每個環節, 這風騷的操作,也是沒誰了。

這個專案做下來,除了沒有涉及到資料抓取(python爬蟲)外,基本上把python 資料處理分析的各個版塊都做了一個完整的貫穿。對此進行歸納總結,算是倒逼自己對所接觸到的知識,進行結構化的梳理和輸出。

探索的問題

主要探尋坦尼克號上的生還率和各因素(客艙等級、年齡、性別、上船港口等)的關係。

獲取資料

我把原始資料 titanic-data.csv 放在和 notebook 檔案同一目錄下,然後通過read_csv 來載入檔案,當然在開始載入資料前,我必須按照需求將需要用到的 Python 包匯入進來。

# 用於資料分析
import pandas as pd
import numpy as np

# 用於繪圖
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

# 讀取前五行資料
data_t = pd.read_csv(`titanic-data.csv`)
data_t.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
# 資料集資訊,包含資料集大小,列名,型別
data_t.info()
data_t.columns.values
複製程式碼
<class `pandas.core.frame.DataFrame`>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            714 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB





array([`PassengerId`, `Survived`, `Pclass`, `Name`, `Sex`, `Age`, `SibSp`,
       `Parch`, `Ticket`, `Fare`, `Cabin`, `Embarked`], dtype=object)
複製程式碼

資料觀察

  • 載入 titanic-data.csv 到一個 DataFrame ,然後用 head() 函式列印出前5行資料(p.s 用 tail() 函式可以列印出後5行)。

  • 通過對資料的初步觀測,這個資料樣本一共有 891 行 * 12 列資料,欄位包含:
    `PassengerId(乘客id)`, `Survived(是否活下來)`, `Pclass(船艙等級)`, `Name(姓名)`, `Sex(性別)`, `Age(年齡)`, `SibSp(兄弟姐妹同行數量)`,`Parch(父母配偶同行數量)`, `Ticket(票)`, `Fare(費)`, `Cabin(船艙)`, `Embarked(上船站)`

  • 其中, 定類變數 包括 Survived,Sex,Embarked, 定序變數 包括 Pclass, 數字變數 包括 PassengerId,Age,SibSp,Parch,Fare

  • 通過觀測發現,Age、Cabin、Embarked 包含了有空值

# 欄位分析
def y(x):
    return data_t[x].unique()
print(`=`*20 + `Survived欄位內容` + `=`*20)
print(y(`Survived`))
print(`=`*20 + `Sex欄位內容` + `=`*20)
print(y(`Sex`))
print(`=`*20 + `Pclass欄位內容` + `=`*20)
print(y(`Pclass`))
print(`=`*20 + `Embarked欄位內容` + `=`*20)
print(y(`Embarked`))
複製程式碼
====================Survived欄位內容====================
[0 1]
====================Sex欄位內容====================
[`male` `female`]
====================Pclass欄位內容====================
[3 1 2]
====================Embarked欄位內容====================
[`S` `C` `Q` nan]
複製程式碼

變數的值

  • Survived 的值:0(死亡),1(存活)
  • Sex 的值:male(男性),female(女性)
  • Embarked的值包含 `S` `C` `Q`
# 顯示重複的資料數量

data_t.duplicated().value_counts()
複製程式碼
False    891
dtype: int64
複製程式碼

重複資料

資料集一共有 891 行資料,不重複。

# 顯示有空值的列
print(data_t[`Age`].isnull().value_counts())
print(`-`*50)
print(data_t[`Cabin`].isnull().value_counts())
print(`-`*50)
print(data_t[`Embarked`].isnull().value_counts())
print(`-`*50)
複製程式碼
False    714
True     177
Name: Age, dtype: int64
--------------------------------------------------
True     687
False    204
Name: Cabin, dtype: int64
--------------------------------------------------
False    889
True       2
Name: Embarked, dtype: int64
--------------------------------------------------
複製程式碼

空值情況

  • Age 一共有 714 行空資料
  • Cabin(船艙)一共有 204 行空資料
  • Embarked(上船站)一共有 2 行空資料。
# 描述性分析
data_t.describe()
複製程式碼
PassengerId Survived Pclass Age SibSp Parch Fare
count 891.000000 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208
std 257.353842 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429
min 1.000000 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400
50% 446.000000 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200
75% 668.500000 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200

描述性統計

  • 在這次旅行的 891 名乘客中,有 38% 的人活了下來,幸運兒。
  • 所有旅客中,年齡最小的只有 0.4 歲,最大的有 80 歲,平均年齡在 28 歲左右。
  • 平均每個乘客有 0.52 個兄弟姐妹陪同,有 0.38 個父母配偶陪同。
  • 有些乘客居然有 8 名同行的人。
  • 旅客為這趟旅行平均花費 32 美元,最高花費 512 美元(貴族吧)

資料清洗(cleanse the data)

題外話
據說資料清洗這一塊在實際業務中大概佔有 80% 的時間,可真是苦逼。

缺失值處理中,我們一般會刪除缺失值。pandas模組中,提供了將包含NaN值的行刪除的方法dropna(),但其實處理缺失值最好的思路是用最接近的資料替換

首先,清洗資料就是處理空值,讓這些空值參與到之後的資料分析中去。其次,我將刪除那些對於資料分析本身並沒有相關性的資料列,比如Cabin(因為一個船艙號對於是否能夠逃生確實沒有任何影響)。最後,我會觀察資料集,看看是否可以創造出一些新的特性,讓我們的分析能夠更直觀快捷。

# 處理空值
data_t[`Age`] = data_t[`Age`].fillna(data_t[`Age`].mean()).astype(np.int64)
data_t[`Embarked`] = data_t[`Embarked`].fillna({"Embarked":"S"},inplace=True)
# 刪除無關的列
data_t = data_t.drop([`Ticket`,`Cabin`],axis=`columns`)
data_t.info()
複製程式碼
<class `pandas.core.frame.DataFrame`>
RangeIndex: 891 entries, 0 to 890
Data columns (total 10 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            891 non-null int64
SibSp          891 non-null int64
Parch          891 non-null int64
Fare           891 non-null float64
Embarked       0 non-null object
dtypes: float64(1), int64(6), object(3)
memory usage: 69.7+ KB
複製程式碼

處理空值和多餘的值

上面用年齡的平均數來代替空值,因為 `S` 出現的頻數最多,咖位最高,所以用 `S` 代替空值。

我刪除掉了 `Ticket`,`Cabin` 兩列資料,實際上這兩列資料對於我們分析資料並沒有太多用處。

資料視覺化分析

資料透視表是 Excel 中最常用的資料彙總分析工具,它可以根據一個或多個制定的維度對資料進行聚合,探索資料內深層次的資訊。

在 pandas 中,同樣提供了pandas.pivot_table 函式來實現這些功能。在接下來的分析中,我們會多次用到這個函式,所以先來熟悉下下這個函式:

pandas.pivot_table 函式中包含四個主要的變數,以及一些可選擇使用的引數。四個主要的變數分別是資料來源 data,行索引 index,列 columns,和數值 values。可選擇使用的引數包括數值的彙總方式,NaN值的處理方式,以及是否顯示彙總行資料等。

基本情況分析

我們先來看下基本情況:891人當中,生還比率與未生還比率是多少?

total_survived = data_t[`Survived`].sum()
total_no_survived = 891 - total_survived

plt.figure(figsize = (10,5)) # 建立畫布
plt.subplot(121) # 新增第一個子圖
sns.countplot(x=`Survived`,data=data_t)
plt.title(`Survived count`)

plt.subplot(122) # 新增第二個子圖
plt.pie([total_survived,total_no_survived],labels=[`Survived`,`No survived`],autopct=`%1.0f%%`)
plt.title(`Survived rate`)

plt.show()
複製程式碼
生還情況

結論:這891名乘客中,生還和未生還的比率分別為 38% 和 62%。

分別探索下 Pclass、Sex、Age 和 Embarked 等與“生還率”的關係.

艙位(Pclass)與生還率關係

把 pivot_table 派上場。

# 不同船艙人數分佈
data_t.pivot_table(values=`Name`,index=`Pclass`,aggfunc=`count`)
複製程式碼
Name
Pclass
1 216
2 184
3 491

傳幾個引數就出來了,是不是很方便。

如果不使用 pivot_table 函式,我們一般用 group_by 來分組聚合。

data_t[[`Pclass`,`Name`]].groupby([`Pclass`]).count()
複製程式碼
Name
Pclass
1 216
2 184
3 491

比較來說,pivot_table 函式可讀性更高。

視覺化操作

plt.figure(figsize = (10,5)) # 建立畫布
sns.countplot(x=`Pclass`,data=data_t)
plt.title(`Person Count Across on Pclass`)

plt.show()
複製程式碼
艙位與生還率的情況

還可以用餅圖。

plt.figure(figsize = (10,5)) # 建立畫布
plt.pie(data_t[[`Pclass`,`Name`]].groupby([`Pclass`]).count(),labels=[`1`,`2`,`3`],autopct=`%1.0f%%`)
plt.axis("equal") #繪製標準的圓形圖

plt.show()
複製程式碼
在這裡插入圖片描述

好了,這是不同艙位的人數分佈情況,我們需要求出的是艙位與生還率的關係。

艙位與生還率的關係

data_t.pivot_table(values=`Survived`,index=`Pclass`,aggfunc=np.mean)
複製程式碼
Survived
Pclass
1 0.629630
2 0.472826
3 0.242363

視覺化操作

plt.figure(figsize= (10 ,5))
sns.barplot(data=data_t,x="Pclass",y="Survived",ci=None) # ci表示置信區間

plt.show()
複製程式碼
在這裡插入圖片描述

結論:頭等艙的生還概率最大,其次是二等艙,三等艙的概率最小。

性別(Sex)與生還率關係
# 不同性別生還率
data_t.pivot_table(values=`Survived`,index=`Sex`,aggfunc=np.mean)
複製程式碼
Survived
Sex
female 0.742038
male 0.188908

視覺化操作

plt.figure(figsize=(10,5))
sns.barplot(data=data_t,x=`Sex`,y=`Survived`,ci=None) 

plt.show()
複製程式碼
在這裡插入圖片描述

結論:女性倖存概率遠遠大於男性。

綜合考慮性別(Sex),艙位(Pclass)與生還率關係
#首先計算不同艙位不同性別的人的生還概率
data_t.pivot_table(values=`Survived`,index=[`Pclass`,`Sex`],aggfunc=np.mean)
複製程式碼
Survived
Pclass Sex
1 female 0.968085
male 0.368852
2 female 0.921053
male 0.157407
3 female 0.500000
male 0.135447

視覺化操作

plt.figure(figsize=(10,5))
sns.pointplot(data=data_t,x=`Pclass`,y=`Survived`,hue=`Sex`,ci=None)

plt.show()
複製程式碼
在這裡插入圖片描述
結論
  • 在各個船艙中,女性的生還率都大於男性。
  • 一二等船艙中女性生還率接近,且遠大於三等艙。
  • 一等艙的男性生還率大於二三等艙,二三等艙男性生還率接近。
年齡(Age)與生還率關係

與上面的艙位、性別這些分類變數不同,年齡是一個連續的數值變數,一般處理這樣的資料型別,我們採用將連續性的變數離散化的方法。

所謂離散化,指的是將某個變數的所在區間分割為幾個小區間,落在同一個區間的觀測值用同一個符號表示,簡單理解就是將屬於統一範圍類的觀測值分為一組。然後分組觀察。

pandas中提供了cut函式,對變數進行離散化分割。

data_t[`AgeGroup`] = pd.cut(data_t[`Age`],5) # 將年齡的列數值劃分為五等份
data_t.AgeGroup.value_counts(sort=False)
複製程式碼
(-0.08, 16.0]    100
(16.0, 32.0]     525
(32.0, 48.0]     186
(48.0, 64.0]      69
(64.0, 80.0]      11
Name: AgeGroup, dtype: int64
複製程式碼

各個年齡段的生還率

data_t.pivot_table(values=`Survived`,index=`AgeGroup`,aggfunc=np.mean)

複製程式碼
Survived
AgeGroup
(-0.08, 16.0] 0.550000
(16.0, 32.0] 0.344762
(32.0, 48.0] 0.403226
(48.0, 64.0] 0.434783
(64.0, 80.0] 0.090909

視覺化操作

plt.figure(figsize=(10,5))
sns.barplot(data=data_t,x=`AgeGroup`,y=`Survived`,ci=None)
plt.xticks(rotation=60) # 設定標籤刻度角度

plt.show()
複製程式碼
在這裡插入圖片描述

結論:兒童少年組的生還率更高。

多因素分析

以上是單獨看年齡/性別/艙位和生還率的關係,下面我們綜合多個因素來看生還率。

年齡(Age),性別(Sex)與生還率關係
data_t.pivot_table(values=`Survived`,index=`AgeGroup`,columns=`Sex`,aggfunc=np.mean)
複製程式碼
Sex female male
AgeGroup
(-0.08, 16.0] 0.673469 0.431373
(16.0, 32.0] 0.718391 0.159544
(32.0, 48.0] 0.791045 0.184874
(48.0, 64.0] 0.916667 0.177778
(64.0, 80.0] NaN 0.090909

視覺化操作

plt.figure(figsize= (10 ,5))
sns.pointplot(data=data_t,x="AgeGroup",y="Survived",hue="Sex",ci=None,
             markers=["^", "o"], linestyles=["-", "--"])
plt.xticks(rotation=60)

plt.show()
複製程式碼
在這裡插入圖片描述

結論:兒童少年,女性的生還率更高。男性生還的基本上都是兒童少年。

年齡(Age),性別(Sex),艙位(Pclass)與生還率關係

data_t.pivot_table(values="Survived",index="AgeGroup",columns=["Sex","Pclass"],aggfunc=np.mean)

複製程式碼
Sex female male
Pclass 1 2 3 1 2 3
AgeGroup
(-0.08, 16.0] 0.833333 1.000000 0.545455 1.000000 0.818182 0.270270
(16.0, 32.0] 0.975610 0.923077 0.521277 0.354167 0.086207 0.138776
(32.0, 48.0] 1.000000 0.904762 0.250000 0.435897 0.076923 0.055556
(48.0, 64.0] 0.941176 0.833333 1.000000 0.269231 0.090909 0.000000
(64.0, 80.0] NaN NaN NaN 0.166667 0.000000 0.000000

視覺化操作

sns.FacetGrid(data=data_t,row="AgeGroup",aspect=2.5)
.map(sns.pointplot,"Pclass","Survived","Sex",hue_order=["male","female"],ci=None,palette="deep", 
     markers=["^", "o"], linestyles=["-", "--"]).add_legend()

plt.show()
複製程式碼
在這裡插入圖片描述

總結

本次分析主要探尋泰坦尼克號上的生還率和各因素(客艙等級、年齡、性別、上船港口等)的關係。

樣本數量為 891,海難發生後,生還者還剩 342 人,生還率為 38%。

泰坦尼克號上有一二三等艙三種船艙型別,其中頭等艙的生還概率最大,其次是二等艙,三等艙的概率最小。

891人中,男性共577人,女性314人,女性生還率遠遠大於男性。可見女性比男性在這次事故中更容易生還,表明“女士優先”的原則在本次事故中得到了發揚。

樣本的 891 人中,最小年齡為 0.42 ,最大年齡 80。按照[(0.34, 16.336] < (16.336, 32.252] < (32.252, 48.168] < (48.168, 64.084] < (64.084, 80.0]]劃分原則,劃分為5組,兒童少年組的生還率最高,年齡越大,生還率越低。“尊老愛幼”的原則在本次事故中沒有很好體現。

樣本的 891 人中,從 C 上船的生還率最高, Q上船的 次之, S上船生還率 最低。

最後需要說明的是,此次資料分析的資料集是從總體中抽樣而來的,如果抽樣無偏,樣本是從總體隨機選取,根據中心極限定理,分析結果具有代表性,如果不是隨機選出,那麼分析結果就不可靠了。

相關文章