数据集来源
https://aistudio.baidu.com/aistudio/datasetdetail/6374
泰坦尼克号乘客数据分析
1 2 3 4 5 6 7 |
# Imports import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline |
1 2 |
# Read titanic_data.csv titanic_df = pd.read_csv('../data/data54777/train.csv') |
1 2 |
# Test data information titanic_df.info() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<class 'pandas.core.frame.DataFrame'> 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 等提供不了和生还有关的有效信息,在分析前可以先去掉。
1 2 3 |
# 删掉用处不大的数据 titanic_df = titanic_df.drop(['PassengerId','Name','Ticket'], axis = 1) titanic_df.info() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<class 'pandas.core.frame.DataFrame'> 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 等字段有丢失值,在稍后的分析中应该先处理丢失值问题。
基本情况
1 2 3 4 |
#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)) |
1 |
生还者 342 人,549 人未生还。 |
1 2 3 4 5 6 7 8 9 10 |
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 根据乘客客舱等级进行生存率分析
不同级别客舱的人数和比例
1 |
titanic_df[['Pclass','Survived']].groupby(['Pclass']).count() |
Survived | |
---|---|
Pclass | |
1 | 216 |
2 | 184 |
3 | 491 |
1 2 3 4 5 6 7 8 |
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%。
不同级别客舱生还人数和占总生还人数的比例
1 2 |
survived_df = titanic_df[titanic_df[ 'Survived'] == 1 ] survived_df[['Pclass','Survived']].groupby(['Pclass']).sum() |
Survived | |
---|---|
Pclass | |
1 | 136 |
2 | 87 |
3 | 119 |
1 2 3 4 5 6 7 8 9 10 |
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%。
不同客舱分别的生还和未生还人数及生还率
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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 根据乘客性别进行生存率分析
船上男女人数及比例?
1 2 3 |
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)) |
1 |
male:female = 577:314 |
1 2 3 4 5 6 7 |
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() |
存活的男女数量及男女比例?
1 2 3 |
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)) |
1 |
survived_male:survived_femal = 109:233 |
1 2 3 4 5 6 7 8 |
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中的条形顺序? |
男性的生还数量及生还率?
1 2 |
male_df = titanic_df[titanic_df['Sex'] == 'male'] male_df['Survived'][male_df['Survived'] == 1].count() |
1 |
109 |
1 2 3 4 5 6 7 |
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%。
女性的生还数量及生还率?
1 2 3 4 5 6 7 8 9 |
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%。
1 2 3 |
survived_by_pclass = titanic_df.groupby('Sex')['Survived'].mean() survived_by_pclass.plot(kind = 'bar') plt.show() |
Age 根据乘客年龄进行生存率分析
由于 Age 有丢失值,先处理丢失值问题。 Age 的丢失值较多,填充的年龄为年龄平均值的上下一个标准差范围内的随机数。
1 2 3 4 5 6 7 8 9 10 |
# 求年龄的平均值,标准差以及丢失值的数量 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 |
1 2 3 4 5 |
/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. |
年龄分布?
1 2 3 4 5 6 7 8 9 10 |
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() |
1 |
titanic_df['Age'].describe() |
1 2 3 4 5 6 7 8 9 |
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 |
按照年龄,将乘客划分为儿童、少年、成年人和老年人,分析四个群体生还情况
1 2 3 4 |
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 |
1 2 3 4 5 6 |
Age_group (0, 12] 0.579710 (12, 18] 0.393258 (18, 65] 0.366897 (65, 100] 0.125000 Name: Survived, dtype: float64 |
1 |
by_age.plot(kind = "bar") |
1 |
<matplotlib.axes._subplots.AxesSubplot at 0x7faa1e0291d0> |
SibSp 根据乘客是否有兄弟姐妹进行生存率分析
1 2 3 |
# 分为有兄弟姐妹和没有兄弟姐妹两组 sibsp_df = titanic_df[titanic_df['SibSp'] != 0] no_sibsp_df = titanic_df[titanic_df['SibSp'] == 0] |
有兄弟姐妹的乘客的生还人数和生还率
1 2 3 4 5 6 7 8 9 |
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()) |
1 |
151 132 |
有兄弟姐妹的乘客,生还 132 人,生还率为 47%。
没有兄弟姐妹的乘客的生还人数和生还率
1 2 3 4 5 6 7 8 9 |
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()) |
1 |
210 |
没有兄弟姐妹的乘客,共生还 210 人,生还率为 35%。
Parch 根据乘客是否有父母子女进行生存率分析
1 2 3 |
# 分为有父母子女和没有父母子女两组 parch_df = titanic_df[titanic_df['Parch'] == 1] no_parch_df = titanic_df[titanic_df['Parch'] == 0] |
有父母子女的乘客的生还人数和生还率
1 2 3 4 5 6 7 8 9 |
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()) |
1 |
65 |
有父母或子女同船的乘客,生还 65 人,生还率为 55%。
没有父母子女的乘客的生还人数和生还率
1 2 3 4 5 6 7 8 9 |
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()) |
1 |
233 |
Fare 根据票价分布进行生存率分析
1 2 3 4 |
plt.figure(figsize=(15,5)) titanic_df['Fare'].hist(bins = 70) plt.show() |
1 2 |
titanic_df.boxplot(column='Fare', by='Pclass', showfliers=False) plt.show() |
1 |
titanic_df['Fare'].describe() |
1 2 3 4 5 6 7 8 9 |
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 |
1 2 3 4 5 6 7 8 9 |
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) |
1 2 3 4 5 6 |
0 0 22.117887 1 48.395408 0 0 31.388207 1 66.596998 |
左右两边分别是死亡乘客和生还乘客的平均票价. 黑色竖线表示正常值误差范围.
可见,票价与生还有一定相关性,生还者的平均票价要比未生还的高。
Cabin 根据船舱号进行生存率分析
1 |
titanic_df['Cabin'].describe() |
1 2 3 4 5 |
count 204 unique 147 top G6 freq 4 Name: Cabin, dtype: object |
丢失值太多,不能用此数据分析出 Cabin 不同对生存率的影响,丢掉。
1 |
titanic_df.drop("Cabin",axis=1,inplace=True) |
Embarked 根据乘客上船的港口位置进行生存率分析
1 |
titanic_df['Embarked'].describe() |
1 2 3 4 5 |
count 889 unique 3 top S freq 644 Name: Embarked, dtype: object |
Embarked 有两个丢失值, 可以用众数填充
1 2 |
titanic_df[['Survived', 'Embarked']].groupby('Embarked').sum() |
Survived | |
---|---|
Embarked | |
C | 93 |
Q | 30 |
S | 219 |
1 2 |
titanic_df["Embarked"] = titanic_df["Embarked"].fillna("S") embarked_survived_sums = titanic_df[['Survived', 'Embarked']].groupby('Embarked').sum() |
不同港口上船的乘客是否与生还率有关系?
1 2 3 4 5 6 7 8 9 |
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