1. 程式人生 > >python 分析泰坦尼克號生還率

python 分析泰坦尼克號生還率

泰坦尼克號資料集,是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()

# 資料集資訊,包含資料集大小,列名,型別

<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()

描述性統計

  • 在這次旅行的 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上船生還率 最低。

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