携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情
Titanic
赛题介绍
比赛名称:Titanic - Machine Learning from Disaster
赛题任务:预测在 titanic 轮船乘客是否幸存。
赛题数据:乘客基本信息和船票信息。
评价指标:提交 .csv 文件检验准确率。
赛题难度:较低(GettingStarted )。
分析数据集
| Variable | Definition | Key |
|---|---|---|
| survival | Survival(是否幸存) | 0 = No, 1 = Yes |
| pclass | Ticket class(船票等级) | 1 = 1st, 2 = 2nd, 3 = 3rd |
| sex | Sex(性别) | |
| Age | Age in years(年龄) | |
| sibsp | # of siblings / spouses aboard the Titanic(旁系亲戚数量) | |
| parch | # of parents / children aboard the Titanic(直系血亲数量) | |
| ticket | Ticket number(船票编号) | |
| fare | Passenger fare(价格) | |
| cabin | Cabin number(船仓编号) | |
| embarked | Port of Embarkation(上船起始点) | C = Cherbourg, Q = Queenstown, S = Southampton |
了解完每个字段的含义后,接下来完成以下分析工作:字段是否存在缺失值,字段含义和取值空间,字段相关性等,主要目的就是选择影响我们任务目标的特征,对该特征进行学习,达到分类能力。接下来看看整个过程是怎么样吧。
引入依赖
import numpy as np
import pandas as pd
%pylab inline
import seaborn as sns
numpy:用于科学计算
pandas:用于数据处理
seaborn:绘图库,用于数据分析
读取数据
train = pd.read_csv('./data/titanic/train.csv')
test = pd.read_csv('./data/titanic/test.csv')
train.head(10)
使用 pandas 的 read_csv() 方法可以读取文件中的数据,利用 head 方法查看部分数据情况。
每一条数据都是一位乘客的信息,具有着多个特征。我们可以发现一些小的问题:Age 特征数据中包含 NAN等。
分析数据
train.describe(include='all')
train.info()
describe 方法能够对数据进行基础统计分析,可以统计出平均值,最大值等结果。
info 方法能够对每列数据进行基础分析,查看是否存在缺失值,以及数据类型。
根据上面图可以知道:Age,Cabin,Embarked 字段都存在缺失值。
我们对整体数据有着一定了解后,需要去分析每列数据,判断是否对我们目标造成影响,
PassageId & Survived
PassageId 是数据的索引,Survived 是数据的标签,对原始数据分析是无意义,一般分析数据是不考虑着两列。
Pclass
Pclass 是船票等级,数据类型为整型数据,可能取值1 = 1st, 2 = 2nd, 3 = 3rd。
# 字段的分布关系
train['Pclass'].value_counts()
"""
3 491
1 216
2 184
Name: Pclass, dtype: int64
"""
train.groupby('Pclass')['Survived'].mean().plot(kind='bar')
根据分析可以知:数字不同,数量也不同,生存的概率也不同;数字越小,等级越高,生存概率越大。该字段会影响任务目标,故该特征保留。
Name
Name 是乘客姓名,从常识讲,似乎在救援方面不会去参考某人的姓名,但是该数据包含的头衔可以被提取出来单独分析,首先用正则表达式从 Name 字段提取特征 Title。
train['Title'] = train['Name'].str.extract(' ([A-Za-z]+)\.')
test['Title'] = test['Name'].str.extract(' ([A-Za-z]+)\.')
有着不同的头衔可能与乘客生还率相关,涉及到乘客社会地位,后面可以使用头衔对 Age 填充数据起到促进作用,首先需要对 Title 进行分组,提取到的太多了,需要进行聚合,观察与生还率相关程度。
train['Title'].replace(['Capt', 'Col', 'Major', 'Dr', 'Rev'],'Officer', inplace=True)
train['Title'].replace(['Don', 'Sir', 'the Countess', 'Countess', 'Dona', 'Lady'], 'Royalty', inplace=True)
train['Title'].replace(['Mme', 'Ms', 'Mrs'],'Mrs', inplace=True)
train['Title'].replace(['Mlle', 'Miss'], 'Miss', inplace=True)
train['Title'].replace(['Master','Jonkheer'],'Master', inplace=True)
train['Title'].replace(['Mr'], 'Mr', inplace=True)
train[['Title','Survived']].groupby(['Title']).mean().plot.bar()
根据图片显示,不同的头衔乘客生还率有着显著的区别,故该特征保留。
Sex
Sax 是乘客性别,当出现危险时候,普遍的逃生策略为:妇女和儿童优先,Sex 对生还率还是会有着一定影响力的。
sns.barplot(x='Sex', y='Survived', data=train)
可以很直观发现,女性的生还率明显高于男性生还率。
Age
Age 指乘客年龄,当出现危险时候,普遍的逃生策略为:妇女和儿童优先,年龄也会对生还率造成一定影响,但是 Age 字段存在大量缺失值,我们需要 Age 进行填补,乘客的年龄可以根据头衔划分出多个区间,根据区间去寻找生还率相关性。
# 将值 NAN 补充成 -0.5
train['Age'] = train['Age'].fillna(-0.5)
test['Age'] = test['Age'].fillna(-0.5)
# age进行分组
train['AgeGroup'] = pd.cut(train['Age'], [-1, 0, 5, 12, 18, 24, 60, np.inf],
labels = ['Unkonw', 'Baby', 'Child', 'Teenager', 'Student', 'Adult', 'Senior'])
test['AgeGroup'] = pd.cut(test['Age'], [-1, 0, 5, 12, 18, 24, 60, np.inf],
labels = ['Unkonw', 'Baby', 'Child', 'Teenager', 'Student', 'Adult', 'Senior'])
train[['AgeGroup', 'Survived']].groupby(['AgeGroup']).mean().plot.bar()
至于如何补足年龄,可以根据头衔进行分组,求出每个头衔的平均年龄值,去补足每一个年龄值为 NAN 的数据。
train[['Title','Age']].groupby(['Title']).describe()
SibSp & Parch
SibSp 代表乘客非直系亲属的数量,Parch 代表直系亲属的数量,这两个字段可能会对乘客生还率造成一定影响,一定数量的家庭一般都会一起生还。
sns.barplot(x='SibSp', y='Survived', data=train)
sns.barplot(x='Parch', y='Survived', data=train)
Ticket
Ticket 指船票的编号,其实与生还率没用存在一定相关性,不保留。
量化数据
不同的字段具有着不同值,我们需要对这些值进行量化,全部转化成数字,方便模型进行使用。一些特征的值是文本的形式,往往这样的特征需要转换为数值型的特征才能进行建模分析。
for col in ['Cabin', 'Embarked', 'AgeGroup', 'Title']:
lbl = LabelEncoder()
train[col] = train[col].astype(object)
test[col] = test[col].astype(object)
train[col] = train[col].fillna('-1')
test[col] = test[col].fillna('-1')
lbl.fit(list(train[col]) + list(test[col])) # 取值空间
train[col] = lbl.transform(train[col])
test[col] = lbl.transform(test[col])
划分数据集
将数据集划分成训练集和测试集,训练集去进行训练,保证模型参数更新,测试集主要测试模型参数是否正确,是否符合预期。
from sklearn.model_selection import train_test_split
x_train, x_val, y_train, y_val = train_test_split(train.drop(['PassengerId','Survived'], axis=1),
train['Survived'])
构建模型训练
此问题是分类问题,故采用逻辑回归模型进行处理。
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()
clf.fit(x_train, y_train)
clf.score(x_val, y_val)
最后对 kaggle 任务的测试集进行测试,得出结果后按要求写入 .csv 文件中,进行提交即可。