数据集来源
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()

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

海难发生前,一等舱、二等舱、三等舱的乘客分别为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()

海难发生后,一等舱、二等舱、三等舱的乘客人数变为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()

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

存活的男女数量及男女比例?
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中的条形顺序?

男性的生还数量及生还率?
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()

男性生还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()

女性生还 233 人,生还率为 74%。远远高于男性的 19%。
survived_by_pclass = titanic_df.groupby('Sex')['Survived'].mean()
survived_by_pclass.plot(kind = 'bar')
plt.show()

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

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

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

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

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

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

233
Fare 根据票价分布进行生存率分析
plt.figure(figsize=(15,5))
titanic_df['Fare'].hist(bins = 70)
plt.show()

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

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)

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

从登船人数来看, 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 生还率最低。
分析限制讨论
- 此数据并非全部乘客的数据,据了解,泰坦尼克号上共有乘客 2224 人,而本数据集共有 891 人。如果该数据集是从 2224 人中随机选出,根据中心极限定理,该样本也足够大,分析结果有代表性;如果不是随机选出,那么分析结果就不可靠了。
- 可能还有其他因素影响生还情况。比如乘客的国别是否与生还状况有关系?乘客的身高是否与生还状况有关系?乘客是否会游泳是否和生还情况有关系?
Views: 139
