你在泰坦尼克号上你能活下来吗?
泰坦尼克号的沉没是历史上最具影响力的海难之一,在1912年4月15日,泰坦尼克号的处女航中,与冰山相撞后沉没。在当时,船上没有足够的救生艇供所有人使用,导致2224名乘客和机组人员中的1502人死亡。虽然幸存有一些运气成分,但似乎有些人比其他人更有可能生存。
泰坦尼克号预测项目从kaggle建站开始,已经经历了很多大佬的分析建模,有2万多的团队参与过该项目,是你加入kaggle最好的项目之一。
- 数据来源:https://www.kaggle.com/c/titanic/overview
- 本文主要是根据解决《泰坦尼克号》竞赛和Manav Sehgal分享和一些其他来源的出色分享创建的,主要目的是为了对机器学习的各位提供一些项目实践,原文地址如下:
- https://www.kaggle.com/startupsci/titanic-data-science-solutions
- A journey through Titanic
- Getting Started with Pandas: Kaggle’s Titanic Competition
- Titanic Best Working Classifier
先想明白我们怎么去做
参考《数据科学解决方案》一书,建模的7个流程:
- 定义问题,确定问题知道我们要做什么
- 获取数据,一般是指训练和测试数据。
- 数据清洗,得到一份干净好用的数据
- 数据分析,探索数据,为后续建模做准备。
- 建模,预测和解决问题。
- 可视化报告,呈现问题的解决步骤和最终解决方案。
- 得到结果。
建模流程
确定问题
每个数据集提出的同时也会伴随着问题,kaggle会给与数据说明(https://www.kaggle.com/c/titanic/overview/description ),我们的问题很简单: “什么样的人更有可能生存呢?”
在泰坦尼克竞赛中,我们可以访问两个类似的数据集,训练集和测试集,字段包括乘客信息,例如姓名、年龄、性别、社会经济舱等。训练集为“ train.csv”,测试集为“ test.csv”。Train.csv将包含一部分乘客的详细信息(准确地说是891位乘客),并且重要的是,它会告诉我们他们是否幸存下来。“ test.csv”数据集包含类似的信息,但没有透露每位乘客的是否存活,我们的工作就是利用train.csv的数据训练出模型,去预测机上其他418名乘客(在test.csv中找到)是否幸免于难。
获取数据
kaggle 提供了很方便的下载方式,可以在数据界面中找到并下载数据:https://www.kaggle.com/c/titanic/overview/description
导包
# 导入数据分析一些常用库
import pandas as pd
import numpy as np
import random as rnd
# pd.options.display.max_columns = None
# 可视化包
import seaborn as sns
import matplotlib.pyplot as plt
plt.style.use("seaborn")
%matplotlib inline
sns.set(font="simhei")
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置加载的字体名
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
# 机器学习包
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC, LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import Perceptron
from sklearn.linear_model import SGDClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.tree import DecisionTreeClassifier
导入数据
train_df = pd.read_csv('train.csv')
test_df = pd.read_csv('test.csv')
combine = [train_df, test_df]
预览数据
# 看一下我们有那些字段
print(train_df.columns.values)
['PassengerId' 'Survived' 'Pclass' 'Name' 'Sex' 'Age' 'SibSp' 'Parch'
'Ticket' 'Fare' 'Cabin' 'Embarked']
# 简单看一下我们的数据
train_df.head(3)
PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S |
1 | 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Th... | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C |
2 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S |
train_df.tail(3)
PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
888 | 889 | 0 | 3 | Johnston, Miss. Catherine Helen "Carrie" | female | NaN | 1 | 2 | W./C. 6607 | 23.45 | NaN | S |
889 | 890 | 1 | 1 | Behr, Mr. Karl Howell | male | 26.0 | 0 | 0 | 111369 | 30.00 | C148 | C |
890 | 891 | 0 | 3 | Dooley, Mr. Patrick | male | 32.0 | 0 | 0 | 370376 | 7.75 | NaN | Q |
数据清洗
字段整理
- PassengerId 用户编号:目前作为用户唯一标识,此处无特别意义(有些编号是具有价值的,比如身份证)
- Survived 是否幸存:目标字段,是我们要预测的数据
- Pclass 用户阶级:分类字段,1为最高级,3为最低级
- Name 姓名:可以看出家族关系
- Sex 性别
- Age 年龄
- SibSp:泰坦尼克号上与乘客同行的兄弟姐妹(Siblings)和配偶(Spouse)数目
- Parch:描述了泰坦尼克号上与乘客同行的家长(Parents)和孩子(Children)数目
- Ticket 船票号
- Fare 票价
- Cabin 船舱号
- Embarked 乘客上船时的港口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L2En3s3d-1614530159408)(attachment:image.png)]
识别特征类型
特征主要类型有:时间型、数值型、类别型、文本型
哪些特征是分类型特征?
类别型特征将相似属性归为一类,但是大多数模型都不能直接处理文本型数据,必须要转换为数值型才能使用。
类别型特征可以分为定类变量、定序变量、定距变量和定比变量。
- 定类变量:如性别(男、女、其他),三种取值之间是相互独立的,彼此之间完全没有关系,这种变量称之为名义变量。
- 定序变量:如学历(小学、初中、高中),三种取值不是完全独立的,我们可以明显看出,在性质上可以有高中>初中>小学这样 的联系,学历有高低,但是学历的取值之间却不是可以计算的,我们不能说小学 + 某个取值 = 初中。这是有序变 量。
- 定距变量:如温度(>25摄氏度、>30摄氏度 、>35摄氏度),各个取值之间有联系,且是可以互相计算的,而且两者的差值有 意义。比如35摄氏度 - 25摄氏度 = 10摄氏度,分类之间可以通过数学计算互相转换。这是有距变量。
- 定比变量:如质量(>10kg、>50kg、>100kg),各个取值之间有联系,不仅可以计算差值,还可以计算其商值。
定序变量:Pclass 用户阶级:分类字段,1为最高级,3为最低级
定类变量:Sex 性别,Embarked 乘客上船时的港口,Survived 是否幸存
哪些特征是数值型特征?
数值型随样本的不同而进行变化,一般分为连续型,离散型,经常使用归一化,离散化等方法进行处理
连续型:Age 年龄,fare 票价。
离散型:SibSp,Parch。
哪些特征是文本型特征?
文本型:Name,姓名中有很多符号,也存在一些错别字的问题
还有一些混合型特征
混合型数据特征:Ticket 船票号,Cabin 船舱号
- 还有1个特征: PassengerId 用户编号(无意义,后续会删除)
数据清洗
空值,数据类型
空值:
训练数据集空值排序:Cabin > Age > Embarked。
测试数据集空值排序:Cabin > Age 。
各特征的数据类型是什么?
训练集:7个特征是整数或浮点数,字符串对象5个。
测试集:6个特征是整数或浮点数,字符串对象5个。
print(train_df.info())
print("--"*20)
print(test_df.info())
<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
None
----------------------------------------
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 11 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 418 non-null int64
1 Pclass 418 non-null int64
2 Name 418 non-null object
3 Sex 418 non-null object
4 Age 332 non-null float64
5 SibSp 418 non-null int64
6 Parch 418 non-null int64
7 Ticket 418 non-null object
8 Fare 417 non-null float64
9 Cabin 91 non-null object
10 Embarked 418 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 36.0+ KB
None
- 通过训练集各个特征的分布情况,我们可以得到一些很有用的信息:
- 训练集中有891条数据,泰塔尼克号实际有2224个客户,占旅客实际数量的40%
- 是否幸存是只有0或1的分类特征
- 约有38%的样本存活下来,但泰坦尼克号实际存活率为32%
- 大多数乘客(> 75%)没有和父母或孩子一起旅行
- 近30%的乘客有兄弟姐妹和/或配偶
- 票价差异很大,只有极少的乘客(<1%)支付的费用高达512美元
- 65-80岁年龄段的老年乘客很少(<1%)。
下面会有具体的数据展示
数值型分布
train_df.describe()
PassengerId | Survived | Pclass | Age | SibSp | Parch | Fare | |
---|---|---|---|---|---|---|---|
count | 891.000000 | 891.000000 | 891.000000 | 714.000000 | 891.000000 | 891.000000 | 891.000000 |
mean | 446.000000 | 0.383838 | 2.308642 | 29.699118 | 0.523008 | 0.381594 | 32.204208 |
std | 257.353842 | 0.486592 | 0.836071 | 14.526497 | 1.102743 | 0.806057 | 49.693429 |
min | 1.000000 | 0.000000 | 1.000000 | 0.420000 | 0.000000 | 0.000000 | 0.000000 |
25% | 223.500000 | 0.000000 | 2.000000 | 20.125000 | 0.000000 | 0.000000 | 7.910400 |
50% | 446.000000 | 0.000000 | 3.000000 | 28.000000 | 0.000000 | 0.000000 | 14.454200 |
75% | 668.500000 | 1.000000 | 3.000000 | 38.000000 | 1.000000 | 0.000000 | 31.000000 |
max | 891.000000 | 1.000000 | 3.000000 | 80.000000 | 8.000000 | 6.000000 | 512.329200 |
类别型特征的分布
姓名在数据集中是唯一的(count = unique = 891)
性别变量有2个值,其中男性占65%(top=男性,freq = 577 / count = 891)。
船舱号在样本中具有多个重复项。也可以看出,有几个乘客共用一个船舱。
港口有3个可能的值。大多数乘客使用的S端口(top= S)
船票号具有很高的重复率(unique = 681),为22%。
# 类别型分布
train_df.describe(include=['O'])
Name | Sex | Ticket | Cabin | Embarked | |
---|---|---|---|---|---|
count | 891 | 891 | 891 | 204 | 889 |
unique | 891 | 2 | 681 | 147 | 3 |
top | Slabenoff, Mr. Petco | male | 1601 | G6 | S |
freq | 1 | 577 | 7 | 4 | 644 |
数据探索及猜想
数据分析猜想
基于到目前为止完成的数据分析,我们得出以下假设,在采取适当措施之前,我们可能会进一步验证这些假设。
1. Correlating.相关性
我们想知道每个特征与生存率的关联程度。找到他们的相关关系,尽可能在早期就去做它,并将相关性与项目后期的建模相关性进行匹配。
2. Completing.完成
我们可能要完成“年龄”特征,因为它肯定与生存相关。
我们可能要完成“港口”特征,因为它也可能与生存或其他重要功能相关。
3. Correcting.纠正
船票号特征可能会从我们的分析中删除,因为它包含很高的重复率(22%),并且船票号与生存率之间可能没有关联。
船舱号特征可能由于高度不完整或在训练和测试数据集中包含许多空值而被删除。
游客ID可能会从训练数据集中删除,因为它对生存没有帮助,没什么意义。
姓名特征是相对非标准的,可能不会直接有助于生存分析,因此可能会被放弃。
4. Creating.创建
我们可能想基于Parch和SibSp创建一个称为“家庭”的新特征,以获取船上家庭成员的总数。
我们可能要设计名称特征,以将姓提取为新特征。
我们可能要为年龄段创建新功能。这会将连续的数字特征转换为序数分类特征。
如果它有助于我们的分析,我们可能还想创建一个票价范围特征。
5. Classifying.分类
我们也可以根据前面提到的问题描述增加假设。
女性(性别=女性)更有可能存活下来。
儿童(年龄<?)存活的可能性更高。
上等乘客(Pclass = 1)更有可能幸存下来。
透视表分析
透视表分析,类似Excel中的数据透视表,可以看到数据的分布趋势
为了确认我们的一些观察和假设,我们可以通过使特征独立来快速分析特征的相关性。在此阶段,我们只能对没有任何空值的特征执行此操作。对分类型(Sex),有序型(Pclass)或离散型的(SibSp,Parch)的特征这样做也是有意义的。
1. Pclass我们发现Pclass = 1和Survived之间存在显着相关性(> 0.5)。我们决定在模型中包括此功能。
2. 性别,我们观察问题可以发现,即性别=女性具有很高的生存率,为74%。
3. SibSp和Parch这些特征对于某些值零相关。最好是从这些单个特征中派生一个特征或一组特征,做一个更好的特征出来。
# 上等乘客更容易存活
train_df[['Pclass', 'Survived'
]].groupby(['Pclass'],
as_index=False).mean().sort_values(by='Survived',
ascending=False)
Pclass | Survived | |
---|---|---|
0 | 1 | 0.629630 |
1 | 2 | 0.472826 |
2 | 3 | 0.242363 |
# 女性更容易存活
train_df[['Sex', 'Survived']].groupby(['Sex'],as_index=False).mean().sort_values(by='Survived',
ascending=False)
Sex | Survived | |
---|---|---|
0 | female | 0.742038 |
1 | male | 0.188908 |
# 与乘客同行的兄弟姐妹和配偶数量
train_df[["SibSp", "Survived"
]].groupby(['SibSp'],
as_index=False).mean().sort_values(by='Survived',
ascending=False)
SibSp | Survived | |
---|---|---|
1 | 1 | 0.535885 |
2 | 2 | 0.464286 |
0 | 0 | 0.345395 |
3 | 3 | 0.250000 |
4 | 4 | 0.166667 |
5 | 5 | 0.000000 |
6 | 8 | 0.000000 |
# 与乘客同行的家长和孩子的数目
train_df[["Parch"