泰坦尼克号乘员数据分析

数据集来源

https://aistudio.baidu.com/aistudio/datasetdetail/6374

泰坦尼克号乘客数据分析

# Imports
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

%matplotlib inline
# Read titanic_data.csv
titanic_df = pd.read_csv('../data/data54777/train.csv')
# Test data information
titanic_df.info()

RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

可以观察到,PassengerId\Name\Ticket 等提供不了和生还有关的有效信息,在分析前可以先去掉。

# 删掉用处不大的数据
titanic_df = titanic_df.drop(['PassengerId','Name','Ticket'], axis = 1)
titanic_df.info()

RangeIndex: 891 entries, 0 to 890
Data columns (total 9 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Survived  891 non-null    int64  
 1   Pclass    891 non-null    int64  
 2   Sex       891 non-null    object 
 3   Age       714 non-null    float64
 4   SibSp     891 non-null    int64  
 5   Parch     891 non-null    int64  
 6   Fare      891 non-null    float64
 7   Cabin     204 non-null    object 
 8   Embarked  889 non-null    object 
dtypes: float64(2), int64(4), object(3)
memory usage: 62.8+ KB

由此可见,Age/Cabin/Embarked 等字段有丢失值,在稍后的分析中应该先处理丢失值问题。

基本情况

#891人当中,共多少人生还?
total_survived_num = titanic_df['Survived'].sum()
total_no_survived_num = titanic_df.shape[0] - total_survived_num
print ("生还者 {} 人,{} 人未生还。".format(total_survived_num,total_no_survived_num))
生还者 342 人,549 人未生还。
plt.figure(figsize = (10,5))
plt.subplot(121)
sns.countplot(x='Survived', data=titanic_df)
plt.title('Survival count')

plt.subplot(122)
plt.pie([total_no_survived_num, total_survived_num],labels=['No Survived','Survived'],autopct='%1.0f%%')
plt.title('Survival rate') 

plt.show()

png

这891名乘客中,生还和未生还的比例分别为 38% 和 62%。

下面,分别分析 Pclass、Sex、Age、SibSp、Parch、Fare、Cabin 和 Embarked 等与“生还”的关系

Pclass 根据乘客客舱等级进行生存率分析

不同级别客舱的人数和比例

titanic_df[['Pclass','Survived']].groupby(['Pclass']).count()
Survived
Pclass
1 216
2 184
3 491
plt.figure(figsize= (10, 5))
plt.subplot(121)
sns.countplot(x='Pclass', data=titanic_df)
plt.title('Pclass Count') 
plt.subplot(122)
plt.pie(x = titanic_df[['Pclass','Survived']].groupby(['Pclass']).count()['Survived'], labels=['1','2','3'],autopct='%1.0f%%')
plt.title('Pclass Count') 
plt.show()

png

海难发生前,一等舱、二等舱、三等舱的乘客分别为216、184、491人,分别占总人数的 24%, 21%, 55%。

不同级别客舱生还人数和占总生还人数的比例

survived_df = titanic_df[titanic_df[ 'Survived'] == 1 ]
survived_df[['Pclass','Survived']].groupby(['Pclass']).sum()
Survived
Pclass
1 136
2 87
3 119
plt.figure(figsize= (10, 5))
plt.subplot(121)
sns.countplot(x='Pclass', data=survived_df)
plt.title('Pclass Survived') 
plt.ylabel('Survived Count')

plt.subplot(122)
plt.pie(x=survived_df[['Pclass','Survived']].groupby(['Pclass']).sum()['Survived'],\
        labels=['1','2','3'],autopct='%1.0f%%')
plt.show()

png

海难发生后,一等舱、二等舱、三等舱的乘客人数变为136、87、119人,分别占总人数的 40%, 25%, 35%。

不同客舱分别的生还和未生还人数及生还率

pclass1 = titanic_df[titanic_df['Pclass'] == 1]
pclass2 = titanic_df[titanic_df['Pclass'] == 2]
pclass3 = titanic_df[titanic_df['Pclass'] == 3]

plt.figure(figsize=(10,20))
plt.subplot(421)
sns.countplot(x = 'Survived', data = pclass1)
plt.title('Pclass 1') 

plt.subplot(422)
plt.pie([pclass1['Survived'][pclass1['Survived'] == 0].count(),pclass1['Survived'][pclass1['Survived'] == 1].count()],\
labels=['No Survived', 'Survived'],autopct='%1.0f%%')

plt.subplot(423)
sns.countplot(x = 'Survived', data = pclass2)
plt.title('Pclass 2') 

plt.subplot(424)
plt.pie([pclass2['Survived'][pclass2['Survived'] == 0].count(),pclass2['Survived'][pclass2['Survived'] == 1].count()],\
labels=['No Survived', 'Survived'],autopct='%1.0f%%')

plt.subplot(425)
sns.countplot(x = 'Survived', data = pclass3)
plt.title('Pclass 3') 

plt.subplot(426)
plt.pie([pclass3['Survived'][pclass3['Survived'] == 0].count(),pclass3['Survived'][pclass3['Survived'] == 1].count()],\
labels=['No Survived', 'Survived'],autopct='%1.0f%%')

plt.subplot(427)
survived_by_pclass = titanic_df.groupby('Pclass')['Survived'].mean()
survived_by_pclass.plot(kind = 'bar')

plt.show()


png

Sex 根据乘客性别进行生存率分析

船上男女人数及比例?

male_sum = titanic_df['Sex'][titanic_df['Sex'] == 'male'].count()
female_sum = titanic_df['Sex'][titanic_df['Sex'] == 'female'].count()
print ("male:female = {}:{}".format(male_sum,female_sum))
male:female = 577:314
plt.figure(figsize=(10,5))
plt.subplot(121)
sns.countplot(x='Sex', data=titanic_df)
plt.subplot(122)
plt.pie([male_sum,female_sum],\
        labels=['male', 'female'],autopct='%1.0f%%')
plt.show()

png

存活的男女数量及男女比例?

survived_male_sum = survived_df['Sex'][survived_df['Sex'] == 'male'].count()
survived_female_sum = survived_df['Sex'][survived_df['Sex'] == 'female'].count()
print ("survived_male:survived_femal = {}:{}".format(survived_male_sum, survived_female_sum))
survived_male:survived_femal = 109:233
plt.figure(figsize=(10,5))
plt.subplot(121)
sns.countplot(x='Sex', data=survived_df)
plt.subplot(122)
plt.pie([survived_male_sum, survived_female_sum],\
        labels=['male', 'female'],autopct='%1.0f%%')
plt.show()
# 如何改变countplot中的条形顺序?

png

男性的生还数量及生还率?

male_df = titanic_df[titanic_df['Sex'] == 'male']
male_df['Survived'][male_df['Survived'] == 1].count()
109
plt.figure(figsize=(10,5))
plt.subplot(121)
sns.countplot(x = 'Survived', data = male_df)
plt.subplot(122)
plt.pie([male_df['Survived'][male_df['Survived'] == 0].count(),male_df['Survived'][male_df['Survived'] == 1].count()],\
        labels=['No Survived', 'Survived'],autopct='%1.0f%%')
plt.show()

png

男性生还109人,生还率仅为 19%。

女性的生还数量及生还率?

female_df = titanic_df[titanic_df['Sex'] == 'female']

plt.figure(figsize=(10,5))
plt.subplot(121)
sns.countplot(x = 'Survived', data = female_df)
plt.subplot(122)
plt.pie([female_df['Survived'][female_df['Survived'] == 0].count(),female_df['Survived'][female_df['Survived'] == 1].count()],\
        labels=['No Survived', 'Survived'],autopct='%1.0f%%')
plt.show()


png

女性生还 233 人,生还率为 74%。远远高于男性的 19%。

survived_by_pclass = titanic_df.groupby('Sex')['Survived'].mean()
survived_by_pclass.plot(kind = 'bar')
plt.show()

png

Age 根据乘客年龄进行生存率分析

由于 Age 有丢失值,先处理丢失值问题。 Age 的丢失值较多,填充的年龄为年龄平均值的上下一个标准差范围内的随机数。

# 求年龄的平均值,标准差以及丢失值的数量
average_age_titanic   = titanic_df["Age"].mean()
std_age_titanic       = titanic_df["Age"].std()
count_nan_age_titanic = titanic_df["Age"].isnull().sum()

# 求年龄随机数,范围在 (mean - std, mean + std)
rand_1 = np.random.randint(average_age_titanic - std_age_titanic, average_age_titanic + std_age_titanic, size = count_nan_age_titanic)

# 将随机数填充进 Age 的丢失值中
titanic_df["Age"][np.isnan(titanic_df["Age"])] = rand_1
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/ipykernel_launcher.py:10: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  # Remove the CWD from sys.path while we load stuff.

年龄分布?

plt.figure(figsize=(12,5))
plt.subplot(121)
titanic_df['Age'].hist(bins = 70)
plt.xlabel('Age')
plt.ylabel('Num')

plt.subplot(122)
titanic_df.boxplot(column='Age', showfliers=False)

plt.show()

png

titanic_df['Age'].describe()
count    891.000000
mean      29.744299
std       13.522766
min        0.420000
25%       21.000000
50%       29.000000
75%       38.000000
max       80.000000
Name: Age, dtype: float64

按照年龄,将乘客划分为儿童、少年、成年人和老年人,分析四个群体生还情况

bins = [0, 12, 18, 65, 100]
titanic_df['Age_group'] = pd.cut(titanic_df['Age'], bins)
by_age = titanic_df.groupby('Age_group')['Survived'].mean()
by_age
Age_group
(0, 12]      0.579710
(12, 18]     0.393258
(18, 65]     0.366897
(65, 100]    0.125000
Name: Survived, dtype: float64
by_age.plot(kind = "bar")

png

SibSp 根据乘客是否有兄弟姐妹进行生存率分析

# 分为有兄弟姐妹和没有兄弟姐妹两组
sibsp_df = titanic_df[titanic_df['SibSp'] != 0]
no_sibsp_df = titanic_df[titanic_df['SibSp'] == 0]

有兄弟姐妹的乘客的生还人数和生还率

plt.figure(figsize=(10,5))
plt.subplot(121)
sns.countplot(x = 'Survived', data = sibsp_df )

plt.subplot(122)
plt.pie([sibsp_df['Survived'][sibsp_df['Survived'] == 0].count(),sibsp_df['Survived'].sum()],\
        labels=['No Survived', 'Survived'],autopct='%1.0f%%')
plt.show()
print(sibsp_df['Survived'][sibsp_df['Survived'] == 0].count(), sibsp_df['Survived'].sum())

png

151 132

有兄弟姐妹的乘客,生还 132 人,生还率为 47%。

没有兄弟姐妹的乘客的生还人数和生还率

plt.figure(figsize=(10,5))
plt.subplot(121)
sns.countplot(x = 'Survived', data = no_sibsp_df )

plt.subplot(122)
plt.pie([no_sibsp_df['Survived'][no_sibsp_df['Survived'] == 0].count(),no_sibsp_df['Survived'].sum()],\
        labels=['No Survived', 'Survived'],autopct='%1.0f%%')
plt.show()
print(no_sibsp_df['Survived'].sum())

png

210

没有兄弟姐妹的乘客,共生还 210 人,生还率为 35%。

Parch 根据乘客是否有父母子女进行生存率分析

# 分为有父母子女和没有父母子女两组
parch_df = titanic_df[titanic_df['Parch'] == 1]
no_parch_df = titanic_df[titanic_df['Parch'] == 0]

有父母子女的乘客的生还人数和生还率

plt.figure(figsize=(10,5))
plt.subplot(121)
sns.countplot(x = 'Survived', data = parch_df )

plt.subplot(122)
plt.pie([parch_df['Survived'][parch_df['Survived'] == 0].count(),parch_df['Survived'].sum()],\
        labels=['No Survived', 'Survived'],autopct='%1.0f%%')
plt.show()
print(parch_df['Survived'].sum())


png

65

有父母或子女同船的乘客,生还 65 人,生还率为 55%。

没有父母子女的乘客的生还人数和生还率

plt.figure(figsize=(10,5))
plt.subplot(121)
sns.countplot(x = 'Survived', data = no_parch_df)

plt.subplot(122)
plt.pie([no_parch_df['Survived'][no_parch_df['Survived'] == 0].count(),no_parch_df['Survived'].sum()],\
        labels=['No Survived', 'Survived'],autopct='%1.0f%%')
plt.show()
print(no_parch_df['Survived'].sum())


png

233

Fare 根据票价分布进行生存率分析

plt.figure(figsize=(15,5))
titanic_df['Fare'].hist(bins = 70)
plt.show()

png

titanic_df.boxplot(column='Fare', by='Pclass', showfliers=False)
plt.show()

png

titanic_df['Fare'].describe()
count    891.000000
mean      32.204208
std       49.693429
min        0.000000
25%        7.910400
50%       14.454200
75%       31.000000
max      512.329200
Name: Fare, dtype: float64
fare_not_survived = titanic_df["Fare"][titanic_df["Survived"] == 0]
fare_survived     = titanic_df["Fare"][titanic_df["Survived"] == 1]
avgerage_fare = pd.DataFrame([fare_not_survived.mean(), fare_survived.mean()])
std_fare      = pd.DataFrame([fare_not_survived.std(), fare_survived.std()])
avgerage_fare.plot(yerr=std_fare,kind='bar',legend=False,)
plt.show()
print(avgerage_fare)
print(std_fare)


png

           0
0  22.117887
1  48.395408
           0
0  31.388207
1  66.596998

左右两边分别是死亡乘客和生还乘客的平均票价. 黑色竖线表示正常值误差范围.

可见,票价与生还有一定相关性,生还者的平均票价要比未生还的高。

Cabin 根据船舱号进行生存率分析

titanic_df['Cabin'].describe()
count     204
unique    147
top        G6
freq        4
Name: Cabin, dtype: object

丢失值太多,不能用此数据分析出 Cabin 不同对生存率的影响,丢掉。

titanic_df.drop("Cabin",axis=1,inplace=True)

Embarked 根据乘客上船的港口位置进行生存率分析

titanic_df['Embarked'].describe()
count     889
unique      3
top         S
freq      644
Name: Embarked, dtype: object

Embarked 有两个丢失值, 可以用众数填充

titanic_df[['Survived', 'Embarked']].groupby('Embarked').sum()
Survived
Embarked
C 93
Q 30
S 219
titanic_df["Embarked"] = titanic_df["Embarked"].fillna("S")
embarked_survived_sums = titanic_df[['Survived', 'Embarked']].groupby('Embarked').sum()

不同港口上船的乘客是否与生还率有关系?

fig, (axis1,axis2,axis3) = plt.subplots(1,3,figsize=(15,5)) 

sns.countplot(x='Embarked', data=titanic_df, ax=axis1)
sns.countplot(x='Survived', hue="Embarked", data=titanic_df, order=[1,0], ax=axis2)

embark_perc = titanic_df[["Embarked", "Survived"]].groupby(['Embarked'],as_index=False).mean()
sns.barplot(x='Embarked', y='Survived', data=embark_perc,order=['S','C','Q'],ax=axis3)

plt.show()

png

从登船人数来看, S 港口人数最多,C 次之, Q 最少。
从生还率来看, C 港上船的生还率最高, Q 次之, S 生还率最低。

分析总结

总结分为两个部分,分别是本次数据分析得出的规律和对于分析的限制性进行讨论。

数据分析总结

本次分析主要探寻泰坦尼克号上的生还率和各因素(客舱等级、年龄、性别、上船港口等)的关系。

样本数量为 891,海难发生后,生还者还剩 342 人,生还率为 38%。

泰坦尼克号上有一\二\三等舱三种船舱类型。海难发生前,一等舱有 216 人,二等舱 184 人,三等舱 491 人,分别占总人数的 24%, 21%, 55%。海难发生后,一等舱、二等舱、三等舱的乘客人数变为136、87、119人,分别占总人数的 40%, 25%, 35%。一等舱生还率为 63%,二等舱为 47%,三等舱为 24%。可见客舱等级越高,生还率越高。

891 人中,891人中,男性共577人,女性314人,男女比例为 65% 和 35%。海难发生后,男性变为109人,女性变为233人,男女比例变为 32% 和 68%。男性生还109人,生还率仅为 19%。女性生还 233 人,生还率为 74%,远远高于男性的 19%。可见女性比男性在这次事故中更容易生还,表明“女士优先”的原则在本次事故中得到了发扬。

样本的 891 人中,平均年龄约为 30 岁, 标准差 15 岁,最小年龄为 0.42 ,最大年龄 80。按照儿童(0-12)、少年(12-18)、成人(18-65)、老年人(65及以上)划分为四类,四类人的生还率分别为58%, 48%, 39% 和 9%。可见年龄越大,生还率越低。“尊老爱幼”的原则在本次事故中没有很好体现。

有兄弟姐妹的乘客,生还 132 人,生还率为 47%,而没有兄弟姐妹的乘客,共生还 210 人,生还率为 35%。可见有兄弟姐妹同船的生还率比没有兄弟姐妹同船的生还率要高。

有父母或子女同船的乘客,生还 109 人,生还率为 51%。没有父母子女同船的乘客,生还 233 人,生还率仅为 34%。可见有父母或子女同船的生还率比没有的生还率要高。综合前一条分析,可以得出推论,有家人在船上的比没有家人在船上的生还概率要大。

票价与生还有一定相关性,生还者的平均票价要比未生还的高。

S 港口生还人数最多,C 次之, Q 最少。从生还率来看, C 港上船的生还率最高, Q 次之, S 生还率最低。

分析限制讨论

  1. 此数据并非全部乘客的数据,据了解,泰坦尼克号上共有乘客 2224 人,而本数据集共有 891 人。如果该数据集是从 2224 人中随机选出,根据中心极限定理,该样本也足够大,分析结果有代表性;如果不是随机选出,那么分析结果就不可靠了。
  2. 可能还有其他因素影响生还情况。比如乘客的国别是否与生还状况有关系?乘客的身高是否与生还状况有关系?乘客是否会游泳是否和生还情况有关系?

Views: 139

Index