利用python分析泰坦尼克号数据集

1 引言

刚接触python与大数据不久,这个是学长给出的练习题目。知识积累太少,学习用了不少的时间。尽量详细的写,希望对各位的学习有所帮助。

2 背景

2.1 Kaggle

本次数据集来自于Kaggle。Kaggle是一个数据分析建模的应用竞赛平台。想要了解详细资料的小伙伴请自行百度。

2.2 泰坦尼克号

本次问题页面

请到Data页面下载数据集

数据集的各属性在Data页面下有详细介绍。

问题就是以大家熟悉的泰坦尼克号为背景展开的,本次任务的目的就是构建一个可以根据乘客个人信息推测乘客是否生存的数据模型。

3 工具介绍

3.1 Python

我所用的python版本为:Python 3.5.2 。

3.2 Anaconda3

Anaconda 是一个很好用的数据分析工具集,其中的Spyder 与 Jupyter Notebook今后会经常使用,而且使用非常方便。

4 初探数据

相信你已经将数据下载到你的电脑中了,下面我们来将数据经行导入及简单分析。
请先打开Spyder。

4.1 导入训练集数据

import pandas as pd #数据分析
import numpy as np #科学计算
from pandas import Series,DataFrame

data_train = pd.read_csv(r'E:\Data\train.csv') #根据数据位置自行修改

运行后我们会在Spyder窗口右上部看到data_train数据。点击后即可显示数据表格,如下:

4.2 数据简单分析

观察图表我们可以知道,共有891行、12列。这代表本训练集共有891条数据,每条数据有12类信息。包括:
• PassengerId => 乘客ID
• Survived => 获救情况(1为获救,0为未获救)
• Pclass => 乘客等级(1/2/3等舱位)
• Name => 乘客姓名
• Sex => 性别
• Age => 年龄
• SibSp => 堂兄弟/妹个数
• Parch => 父母与小孩个数
• Ticket => 船票信息
• Fare => 票价
• Cabin => 客舱
• Embarked => 登船港口

初步观察,我们会发现一些数据信息值为:nan,这就代表该条数据该类信息缺失。在数据分析中,处理缺失值是一个很重要的步骤。一开始,我们不如统计各类信息的缺失的总体情况,让自己对该数据集有所了解。

我们可以在IPython console框中输入:

data_train.info()

回车运行后,即可出现以下内容:

由此可知,Age(年龄)有714人有记录,Cabin(客舱)有204人有记录,Embarked(登陆港口)有少量缺失。

我们还可以用下列语句进行数据的总体统计:

data_train.describe()

结果如下:

由此我们可知,乘客的平均年龄为29.7,最大年龄为80.0,最小年龄为0.42。获救人数为总体的0.383838,等等。

5 数据图形化分析

进行完总体的初步分析,我们接下来进行数据相关性的分析,为了便于观察,我们利用图表展示。

5.1 乘客各属性

代码:

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['font.family']='sans-serif' 
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
fig = plt.figure()
fig.set(alpha=0.2) # 设定图表颜色alpha参数

plt.subplot2grid((2,3),(0,0)) # 在一张大图里分列几个小图
data_train.Survived.value_counts().plot(kind='bar')# 柱状图
plt.title(u"获救情况 (1为获救)") # 标题
plt.ylabel(u"人数") # Y轴标签

plt.subplot2grid((2,3),(0,1))
data_train.Pclass.value_counts().plot(kind="bar") # 柱状图显示
plt.ylabel(u"人数")
plt.title(u"乘客等级分布")

plt.subplot2grid((2,3),(0,2))
plt.scatter(data_train.Survived, data_train.Age) #为散点图传入数据
plt.ylabel(u"年龄") # 设定纵坐标名称
plt.grid(b=True, which='major', axis='y')
plt.title(u"按年龄看获救分布 (1为获救)")

plt.subplot2grid((2,3),(1,0), colspan=2)
data_train.Age[data_train.Pclass == 1].plot(kind='kde') # 密度图
data_train.Age[data_train.Pclass == 2].plot(kind='kde')
data_train.Age[data_train.Pclass == 3].plot(kind='kde')
plt.xlabel(u"年龄")# plots an axis lable
plt.ylabel(u"密度")
plt.title(u"各等级的乘客年龄分布")
plt.legend((u'头等舱', u'2等舱',u'3等舱'),loc='best') # sets our legend for our graph.

plt.subplot2grid((2,3),(1,2))
data_train.Embarked.value_counts().plot(kind='bar')
plt.title(u"各登船口岸上船人数")
plt.ylabel(u"人数")
plt.show()

结果如下:

如果Spyder无法显示中文标签,可以将代码放入IPython Notebook中运行。
我们可以从这五张图中形象的了解到乘客的信息,获救人数少于未获救人数(之前我们以得到此结论),三等乘客人数最多,获救人员各年龄段分布(第一列第三张图,左边竖列标签为0,右边竖列标签为1),S口岸上船的乘客最多。等等。

这时,我们就要将乘客各属性与其是否获救联系起来:
获救情况和乘客等级是否有关?
获救情况和乘客性别、年龄是否有关?(毕竟,妇女、小孩和老人优先搭乘救生艇)
登船口岸是否是获救因素呢?(虽然感觉关系不大,但是也要考虑全面)

5.2 各属性与获救情况的关联

各乘客等级的获救情况

Survived_0 = data_train.Pclass[data_train.Survived == 0].value_counts() # 未获救
Survived_1 = data_train.Pclass[data_train.Survived == 1].value_counts() # 获救
df = pd.DataFrame({u'获救':Survived_1,u'未获救':Survived_0})
df.plot(kind = 'bar', stacked = True)
plt.title(u'各乘客等级的获救情况')
plt.xlabel(u'乘客等级')
plt.ylabel(u'人数')
plt.show()

根据图表可以清楚看到第一等级的乘客,获救人数多于未获救人数,而其它两个等级的乘客,获救人数则少于未获救人数。
所以,乘客等级与获救情况有关联。

各性别的获救情况

Survived_m = data_train.Survived[data_train.Sex == 'male'].value_counts()
Survived_f = data_train.Survived[data_train.Sex == 'female'].value_counts()
df = pd.DataFrame({u'男性':Survived_m,u'女性':Survived_f})
df.plot(kind = 'bar', stacked = True)
plt.title(u'按性别看获救情况')
plt.xlabel(u'性别')
plt.ylabel(u'人数')
plt.show()

很明显看出,未获救人员中男性乘客比例较大,获救人员中女性乘客比例较大。
那么,可以确定性别也是获救情况的一个重要因素。

根据舱等级和性别的获救情况(第一、二等级为高级舱,第三等级为低级舱)

fig = plt.figure()
plt.title(u'根据舱等级和性别的获救情况')

ax1 = fig.add_subplot(141) # 将图像分为1行4列,从左到右从上到下的第1块
data_train.Survived[data_train.Sex == 'female'][data_train.Pclass != 3].value_counts().plot(kind = 'bar', label = 'female high class', color = '#FA2479')
ax1.set_xticklabels([u'获救',u'未获救'], rotation = 0) # 根据实际填写标签
ax1.legend([u'女性/高级舱'], loc = 'best')

ax2 = fig.add_subplot(142, sharey = ax1) # 将图像分为1行4列,从左到右从上到下的第2块
data_train.Survived[data_train.Sex == 'female'][data_train.Pclass == 3].value_counts().plot(kind = 'bar', label = 'female low class', color = 'pink')
ax2.set_xticklabels([u"未获救", u"获救"], rotation=0)
plt.legend([u"女性/低级舱"], loc='best')

ax3 = fig.add_subplot(143, sharey = ax1)
data_train.Survived[data_train.Sex == 'male'][data_train.Pclass != 3].value_counts().plot(kind = 'bar', label = 'male high class', color = 'lightblue')
ax3.set_xticklabels([u'未获救',u'获救'], rotation = 0)
plt.legend([u'男性/高级舱'], loc = 'best')

ax4 = fig.add_subplot(144, sharey = ax1)
data_train.Survived[data_train.Sex == 'male'][data_train.Pclass == 3].value_counts().plot(kind = 'bar', label = 'male low class', color = 'steelblue')
ax4.set_xticklabels([u'未获救',u'获救'], rotation = 0)
plt.legend([u'男性/低级舱'], loc = 'bast')
plt.show()

很明显高级舱女性的生还率高于低级舱,低级舱男性的死亡率高于高级舱。在四种情况中,高级舱女性的生还率最高,低级舱男性的死亡率最高。
将与获救情况相关联的两种属性结合后,所得到的结果可以更明显知晓他们的相关性。

各登陆港口乘客的获救情况

fig = plt.figure()
fig.set(alpha = 0.2)
Survived_0 = data_train.Embarked[data_train.Survived == 0].value_counts()
Survived_1 = data_train.Embarked[data_train.Survived == 1].value_counts()
df = pd.DataFrame({u'获救':Survived_1,u'未获救':Survived_0})
df.plot(kind = 'bar', stacked = True)
plt.title(u'各登陆港口乘客的获救情况')
plt.xlabel(u'登陆港口')
plt.ylabel(u'人数')
plt.show()

获救情况与上船口岸的联系,根据上图感觉相关性并不强。C港的获救率高一些。

堂兄弟/妹,孩子/父母有几人,对是否获救的影响

g = data_train.groupby(['SibSp','Survived']) # 数据分组
df = pd.DataFrame(g.count()['PassengerId'])
print (df)
g = data_train.groupby(['Parch','Survived'])
df = pd.DataFrame(g.count()['PassengerId'])
print (df)

堂兄弟/妹,孩子/父母有几人,对是否获救的影响并不明显。

按Cabin有无看获救情况

fig = plt.figure()
fig.set(alpha = 0.2)

Survived_cabin = data_train.Survived[pd.notnull(data_train.Cabin)].value_counts()
Survived_nocabin = data_train.Survived[pd.isnull(data_train.Cabin)].value_counts()
df = pd.DataFrame({u'有':Survived_cabin, u'无':Survived_nocabin}).transpose()
df.plot(kind = 'bar', stacked = True)
plt.title(u'按Cabin有无看获救情况')
plt.xlabel(u'Cabin有无')
plt.ylabel(u'人数')
plt.show()

有客舱信息的获救情况较高一点。但情况复杂,比如生还者上岸后进行信息统计的话,就会影响信息有无对获救情况的关系。

6 简单数据预处理

#我们将测试集导入,再将删除Survived数据的训练集与测验集进行合并,这样便于进行数据处理
data_test = pd.read_csv(r'E:\Data\test.csv') # 导入测验集数据

y = data_train['Survived'] # 将训练集Survived 数据存储在y中
del data_train['Survived'] # 删除训练集Survived数据

sum_id = data_test['PassengerId'] # 存储测试集乘客ID

df = pd.merge(data_train, data_test,how='outer') # 合并无Survived数据的训练集与测验集,how = ‘outer’ 意为并集

#删掉无关因素
df = df.drop(['Name','PassengerId','Ticket','Cabin'],axis=1) # 删除姓名、ID、船票信息、客舱信息,axis=0 删除行,=1 删除列

#缺失数据填充
df['Age'] = df['Age'].fillna(df['Age'].mean())  # 用平均值填充空值
df['Fare'] = df['Fare'].fillna(df['Fare'].mean())
df['Embarked'] = df['Embarked'].fillna( df['Embarked'].value_counts().index[0]) # 用数量最多项填充

#将性别与港口用哑变量表示
dumm = pd.get_dummies(df[['Sex','Embarked']]) # '哑变量'矩阵
df = df.join(dumm)
del df['Sex'] // 删除
del df['Embarked']

#数据降维
df['Age'] = (df['Age']-df['Age'].min()) /(df['Age'].max()-df['Age'].min())

df['Fare'] = (df['Fare']-df['Fare'].min()) /(df['Fare'].max()-df['Fare'].min())

#训练模型
data_train = df[:len(data_train)] # 将合并后的数据分离
data_test = df[len(data_train):]

7 训练并预测

from sklearn.cross_validation import train_test_split

X_train, X_val, y_train,y_val = train_test_split(data_train,y,test_size=0.3, random_state=42) # 以7:3(0.3)将训练集与获救结果随机拆分,随机种子为42

from sklearn.linear_model import LogisticRegression # 引入逻辑回归
LR = LogisticRegression()

LR.fit(X_train, y_train) # 训练数据
print('训练集准确率:\n',LR.score(X_train, y_train)) # 分数
print('验证集准确率:\n',LR.score(X_val, y_val))

#预测测验集
pred= LR.predict(data_test) # pred 为预测结果

pred = pd.DataFrame({'PassengerId':sum_id.values, 'Survived':pred}) # 格式化预测结果

pred.to_csv('pred_LR.csv',index=None) # 导出数据

结果:

最后,也可以将导出的csv文件在Kaggle中进行提交。

8 结语

这是个不太复杂的数据处理题目,预测结果只有两种,但是题目所给因素较多,需要经行无关因素排除,排除后要将数据经行预处理。预处理时,先将缺失值进行补全,再进行降维处理,本题在降维前要将分类变量Sex、Embarked变为哑变量。最后进行train_test_split方法拆分数据,利用逻辑回归训练模型。

附:佳句

来了,爱了,给了她一颗星星,走了。
               ——云天明《三体》

以上

posted @ 2017-07-02 15:47  梦想未必轻  阅读(20988)  评论(2编辑  收藏  举报