泰坦尼克号背景介绍
泰坦尼克号是一艘奥林匹克级邮轮,于1912年4月首航时撞上冰山后沉没。泰坦尼克号由位于北爱尔兰贝尔法斯特的哈兰·沃尔夫船厂兴建,是当时最大的客运轮船,由于其规模相当一艘现代航空母舰,因而号称“上帝也沉没不了的巨型邮轮”。在泰坦尼克号的首航中,从英国南安普敦出发,途经法国瑟堡-奥克特维尔以及爱尔兰昆士敦,计划横渡大西洋前往美国纽约市。但因为人为错误,于1912年4月14日船上时间夜里11点40分撞上冰山;2小时40分钟后,即4月15日凌晨02点20分,船裂成两半后沉入大西洋,死亡人数超越1500人,堪称20世纪最大的海难事件,同时也是最广为人知的海难之一。
对泰坦尼克号数据进行分析,哪些因素,会导致乘客的生还率更高。
1.提出问题:什么因素会影响乘客的生还率?
影响乘客生还率的因素很多,这里只讨论乘客的性别、年龄、以及舱位是否对生还率产生影响。
- 1.性别对生还率的影响
- 2.年龄对生还率的影响
- 3.舱位对生还率的影响
- 4.年龄和性别共同对生还率的影响
- 5.年龄和舱位共同对生还率的影响
- 6.性别和舱位共同对生还率的影响
- 7.年龄、性别、舱位共同对生还率的影响
- 这里,年龄、性别、舱位是自变量,生还率是因变量。
(年龄、舱位是数值变量;性别是分类变量)
2.导入包
import pandas as pd
import numpy as np
from pandas import Series,DataFrame
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline #图片在Python中显示
%config inlinebackend.fiture_format='retina' #设置图片清晰度
3.导入数据
titanic_df=pd.read_csv('titanic.csv') #titanic数据包与编辑的notebook在同一文件夹
titanic_df.head() #查看数据的前5行
数据前5行
4.熟悉数据
数据字段说明
- PassengerId: 乘客的id
- Survival: 是否幸存 0 = No, 1 = Yes
- Pclass: 舱位 class 1 = 1st, 2 = 2nd, 3 = 3rd
- Name: 姓名
- Sex: 性别
- Age: 年龄
- SibSp: 船上兄弟姐妹以及配偶的个数
- Parch: 船上父母以及者子女的个数
- Ticket: 船票号码
- Fare: 票价
- Cabin: 船舱号码
- Embarked: 登船码头 C = Cherbourg, Q = Queenstown, S = Southampton
查看数据信息
titanic_df.describe()
数值变量信息
发现:从数据的摘要信息中可以看出,乘客的生还率大约为38%。乘客的年龄比较年轻,平均年龄在30岁左右。3等舱的乘客最多,占50%。
titanic_df.describe(include=[np.object])
分类变量信息
发现:乘客中男性较多,大约占60%
5.数据清洗
titanic_df.info() #查看数据缺失值
<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
从上面的信息中可以看到,乘客的年龄、客舱、登船港口信息不全。
处理缺失值
#Embarked有两个缺失值,这里用众数'S'填充,因为这里缺失的值相比而言非常的少
#所以对分析结果产生不了多大的影响
titanic_df['Embarked']=titanic_df['Embarked'].fillna('S')
#Cabin 列的缺失值太多,所以不考虑Cabin列的值,但仍不建议删除掉
#年龄信息,是将要在下面的分析中用到的,所以需要对它的缺失值进行处理。
#这里用年龄的中位数填充,这会缩小年龄之间的差异性
titanic_df.Age.describe() # 在处理之前,查看Age列的统计值,与处理之后的数据进行对比
count 714.000000
mean 29.699118
std 14.526497
min 0.420000
25% 20.125000
50% 28.000000
75% 38.000000
max 80.000000
Name: Age, dtype: float64
# 重新载入原始数据
titanic_df=pd.read_csv("titanic.csv")
# 计算所有人年龄的均值
age_median1 = titanic_df.Age.median()
# 使用fillna填充缺失值,inplace=True表示在原数据titanic_df上直接进行修改
titanic_df.Age.fillna(age_median1, inplace=True)
# 查看Age列的统计值
titanic_df.Age.describe()
count 891.000000
mean 29.361582 #年龄平均值变小
std 13.019697
min 0.420000
25% 22.000000
50% 28.000000
75% 35.000000
max 80.000000
Name: Age, dtype: float64
* 考虑性别因素,分别用男女乘客各自年龄的中位数来填补
# 重新载入原始数据
titanic_df=pd.read_csv("titanic.csv")
# 分组计算男女年龄的中位数, 得到一个Series数据,索引为Sex
age_median2 = titanic_df.groupby('Sex').Age.median()
# 设置Sex为索引
titanic_df.set_index('Sex', inplace=True)
# 使用fillna填充缺失值,根据索引值填充
titanic_df.Age.fillna(age_median2, inplace=True)
# 重置索引,即取消Sex索引
titanic_df.reset_index(inplace=True)
# 查看Age列的统计值
titanic_df.Age.describe()
count 891.000000
mean 29.441268
std 13.018747
min 0.420000
25% 22.000000
50% 29.000000
75% 35.000000
max 80.000000
Name: Age, dtype: float64
* 同时考虑性别和舱位因素
# 重新载入原始数据
titanic_df=pd.read_csv("titanic.csv")
# 分组计算不同舱位男女年龄的中位数, 得到一个Series数据,索引为Pclass,Sex
age_median3 = titanic_df.groupby(['Pclass', 'Sex']).Age.median()
# 设置Pclass, Sex为索引, inplace=True表示在原数据titanic_df上直接进行修改
titanic_df.set_index(['Pclass','Sex'], inplace=True)
# 使用fillna填充缺失值,根据索引值填充
titanic_df.Age.fillna(age_median3, inplace=True)
# 重置索引,即取消Pclass,Sex索引
titanic_df.reset_index(inplace=True)
# 查看Age列的统计值
titanic_df.Age.describe()
count 891.000000
mean 29.112424
std 13.304424
min 0.420000
25% 21.500000
50% 26.000000
75% 36.000000
max 80.000000
Name: Age, dtype: float64
6.数据探索
# 获取生还乘客的数据
survived_passenger_df=titanic_df[titanic_df.Survived==1]
survived_passenger_df.head(10)
# 这里定义几个常用的方法
# 打印均值
def print_describe(name,label):
print '全体乘客的'+label+':'
print '平均值:'+str(titanic_df[name].mean())
print '最小值:'+str(titanic_df[name].min())
print '最大值:'+str(titanic_df[name].max())
print ''
print '生还乘客的'+label+':'
print '平均值:'+str(survived_passenger_df[name].mean())
print '最小值:'+str(survived_passenger_df[name].min())
print '最大值:'+str(survived_passenger_df[name].max())
# 按照name对乘客进行分组后,计算每组的人数
def group_passenger_count(data,name):
# 按照name对乘客进行分组后,每个组的人数
return data.groupby(name)['PassengerId'].count()
# 计算每个组的生还率
def group_passenger_survival_rate(name):
# 按照name对全体乘客进行分组后,每个组的人数
group_all_passenger_count=group_passenger_count(titanic_df,name)
# 按照name对生还乘客进行分组后,每个组的人数
group_survived_passenger_count=group_passenger_count(survived_passenger_df,name)
# 每个组的生还率
return group_survived_passenger_count/group_all_passenger_count
# 输出饼图
def print_pie(group_data,title):
# 按照name对乘客进行分组后,每个组的人数
group_data.plot.pie(title=title,figsize=(6, 6),autopct='%3.1f%%',startangle = 90,legend=True)
# 输出柱状图
def print_bar(data,title):
bar=data.plot.bar(title=title)
for p in bar.patches:
bar.annotate('%3.1f%%' % (p.get_height()*100), (p.get_x() * 1.005, p.get_height() * 1.005))
性别对生还率的影响
titanic_df[['Survived','Sex']].groupby('Sex').mean
titanic_df.pivot_table(values='Survived',index='Sex',aggfunc=np.mean)
#全体乘客的性别比例图
by_Sex=titanic_df.groupby('Sex')['Sex'].count()
plt.pie(by_Sex,labels=['femal','male'],autopct='%1.2f%%')
plt.axis('equal')
plt.show()
#生还乘客性别比例图
titanic_df1=titanic_df[titanic_df.Survived==1]
titanic_survived=titanic_df1[['Survived','Sex']].groupby('Sex').count()
plt.pie(titanic_survived,labels=['male','femal'],autopct='%.2f%%')
plt.axis('equal')
plt.show()
#不同性别的生还率
sns.barplot(data=titanic_df,x='Sex',y='Survived',ci=None)
全部乘客中,只有35.24%的女性,而生还的乘客中,女性占到了68.13% 。
女性的生还率达到了74.2%,而男性的生还率只有18.9% 。
我们可以看出,女性的生还率更高。
年龄对生还概率的影响
titanic_sex1=titanic_df['Age'][titanic_df['Survived']==1]
titanic_sex0=titanic_df['Age'][titanic_df['Survived']==0]
plt.hist([titanic_sex1,titanic_sex0],
stacked=True #两幅图重合
label=['Rescued','Not Saved']) #标签
plt.legend() #显示标签
plt.title('Age-Survived') #显示标题
#定义函数
titanic_survived=titanic_df[titanic_df['Survived']==1]
def describe_value(data,label):
print('全体乘客的:'+label)
print('最大值:' ,titanic_df[data].max())
print( '最小值:',titanic_df[data].min())
print('平均值:',titanic_df[data].mean())
print ('生还乘客的:'+label)
print ('最大值:' ,titanic_survived[data].max())
print ('最小值:' ,titanic_survived[data].min())
print ('平均值:' ,titanic_survived[data].mean())
describe_value('Age','年纪')
全体乘客的:年纪
最大值: 80.0
最小值: 0.42
平均值: 29.11242424242424
生还乘客的:年纪
最大值: 80.0
最小值: 0.42
平均值: 28.108684210526317
可以看出两者的你年龄均值非常接近
从直方图中看,两者的分布也非常接近
两者中间都有一个柱子凸起,是因为年龄的缺失值是用均值填充的
#对年龄进行均匀分组,按照10岁一组进行划分
bins=np.arange(0,90,10)
titanic_df['Age_band']=pd.cut(titanic_df.Age,bins)
#每个年龄段里面,男、女的人数
titanic_ageband=titanic_df.groupby(['Age_band','Survived'])['Age_band'].count()
#每个年龄段的生还率
titanic_ageband_survived=titanic_df.groupby('Age_band')['Survived'].mean()
titanic_ageband_survived.plot.bar(title='Survived rate by age')
plt.ylabel('Survival rate')
plt.axhline(y=0.415,color='r',linestyle='--')
plt.axhline(y=0.351,color='g',linestyle='--')
发现:这里可以看出有几个年龄段对是生还率有明显的影响,如 0-10岁和 30-40岁
#可视化每个年龄段里面的男、女人数
titanic_ageband.unstack().plot(kind='bar',stacked=True)
plt.title('Survived count by age')
plt.ylabel('Survived count')
sns.barplot(data=titanic_df,x='Age_band',y='Survived',ci=None)
plt.axhline(y=0.415,color='r',linestyle='--')
plt.axhline(y=0.351,color='g',linestyle='--')
可以看出,在0-10和30-40岁年龄段的生还率高于平均水平,而20-30和60-70岁年龄段的生还率率低于平均水平
得出结论:0-10岁和30-40岁的生还率高于平均值,20-30岁和60-70岁的生还率低于平均值
0-10岁的生还率最高,用均值填充缺失的年龄值可能造成,年龄差异的缩小
舱位与生还概率的关系
#全体乘客的舱位比例图
by_pclass=titanic_df.groupby('Pclass')['Pclass'].count()
plt.pie(by_pclass,labels=(1,2,3),autopct='%1.1f%%')
plt.axis('equal')
plt.show()
可以看出三等级的人数占了总体人数的一半多
#生还乘客舱位比例图
titanic_df3=titanic_df[titanic_df.Survived==1]
titanic_survived=titanic_df3[['Survived','Pclass']].groupby('Pclass').count()
plt.pie(titanic-survived,labels=(1,2,3),autopct='%1.1f%%')
plt.axis('equal')
plt.show()
全体乘客中三等级人数占了一半多,但是生还乘客中,三等级的比例还有没有1等级的多
得出结论:等级对生还率有影响
#不同舱位的生还率
titanic_df['Pclass','Survived'].groupby('Pclass').mean()
titanic_df.pivot_table(values='Survived',index='Pclass',aggfunc=np.mean)
sns.barplot(data=titanic_df,x='Pclass',y='Survived',ci=None)
可以看出1等级的生还率明显大于2、3等级
结论:"1"等级的生还率>“2”等级>"3"等级 ; "1"等级的生还率最高
年龄和性别与生还率的关系
#乘客中年龄和性别的人数统计
titanic_df4=titanic_df.pivot_table(values='Survived',index='Age_band',columns='Sex',aggfunc='count')
titanic_df4.plot(kind='bar')
#生还乘客中年龄和性别的人数统计
titanic_df5=titanic_df[titanic_df.Survived==1]
titanic_survived=titanic_df5.pivot_table(values='Survived',index='Age_band',columns='Sex',aggfunc='count')
titanic_survived.plot(kind='bar')
#年龄和性别的生还率
sns.barplot(data=titanic_df,x='Age_band',y='Survived',hue='Sex',ci=None)
plt.axhline(y=0.4,color='r',linestyle='--')
从图中看出:年龄段在20-40岁之间人数最多,但这个年龄段的生还率却不是最高的,反而年龄较小(0~10岁)和年龄较大(50-70岁)之间的生还率是最高的。
男性的人数明显多于女性,但女性的生还率明显高于男性,且女性的生还率都在40%以上。
综上可以看出,性别对生还率的影响大于年龄的影响。
年龄和舱位与生还率的关系
#乘客中年龄和舱位的人数统计
titanic_df6=titanic_df.pivot_table(values='Survived',index='Age_band',columns='Pclass',aggfunc='count')
titanic_df6.plot(kind='bar')
#生还乘客中年龄和舱位的人数统计
titanic_df7=titanic_df[titanic_df.Survived==1]
titanic_survived=titanic_df7.pivot_table(values='Survived',index='Age_band',columns='Pclass',aggfunc='count')
titanic_survived.plot(kind='bar')
#乘客中年龄和舱位的生还概率
sns.barplot(data=titanic_df,x='Age_band',y='Survived',hue='Pclass',ci=None)
plt.axhline(y=0.4,color='g',linestyle='--')
从图中看出:3舱的人数最多,但3舱的生还率最小。而在0-50岁的年龄区间,1、2舱舱的生还率都大于40%。
同一个年龄段,除了0-10岁和60-70岁,区间外,1舱的生还率最高。
不同年龄段,也是1舱的生还率>2舱>3舱
性别和舱位与生还率的关系
#乘客中性别和舱位的人数统计
titanic_df8=titanic_df.pivot_table(values='Survived',index='Pclass',columns='Sex',aggfunc='count')
titanic_df8.plot(kind='bar')
#生还乘客中性别和舱位的人数统计
titanic_df9=titanic_df[titanic_df.Survived==1]
titanic_survived=titanic_df9.pivot_table(values='Survived',index='Pclass',columns='Sex',aggfunc='count')
titanic_survived.plot(kind='bar')
#性别、舱位与生还率的关系
sns.barplot(data=titanic_df,x='Pclass',y='Survived',hue='Sex',ci=None)
从图中可以看出,1号舱与2号舱的人数差不多,且都小于3号舱人数,且3个船舱中男性人数均多于女性人数。
从生还人数中来看,女性生还人数高于男性生还人数,且1号舱的生还人数高于2、3号舱生还人数。
从生还率来看,1、2号舱女性生还率最高,达到90%,3号舱女性生还率大约为50%。男性的生还率普遍低于40%,但男性1号舱的生还率高于男性2号、3号生还率。
所以,性别和舱位均对生还率产生影响。
年龄、性别、舱位与生还率关系
#乘客中年龄、性别、舱位人数统计
titanic_df10=titanic_df.pivot_table(values='Survived',index=['Age_band','Pclass'],columns='Sex',aggfunc='count')
titanic_df10.plot(kind='bar')
#生还乘客中年龄、性别、舱位的人数统计
titanic_df11=titanic_df[titanic_df.Survived==1]
titanic_survived=titanic_df11.pivot_table(values='Survived',index=['Age_band','Pclass'],columns='Sex',aggfunc='count')
titanic_survived.plot(kind='bar')
#年龄、性别、舱位与生还率关系
sns.FacetGrid(titanic_df,'AgeBand',aspect=1.5).map(sns.pointplot,'Pclass','Survived','Sex',hue_order=['male','female'],palette='deep',ci=None)
结论
通过分析,可以看出对生还率影响最大的因素是乘客性别,其次是等级,最后年龄段也对生还率有影响
分析的局限性
- 这里并没有从统计上分析得出这些结果的偶然性,所以并不知道这里的结果是真正的差异造成的还是噪音造成的
- 年龄字段有一些缺失值,因为是连续数据这里用的是全体乘客年龄的均值填充缺失值,这样会缩小年龄之间的差异,也会影响分析结果
可能影响生还率的其他因素
- 还有一些因素可能会影响生还率,不如乘客的职业、身体素质、求生意志等,但是数据中并没有个给出
结果的相关性
这里的数据并非通过试验得出,所以无法说自变量之间的因果性,只能说她们之间有相关性