以Kaggle上的一道经典题Titanic为例,总结一下数据分析的一些方法。
题目说明
RMS泰坦尼克号的沉没是历史上最著名的沉船事件之一。
1912年4月15日,泰坦尼亚号在首次航行中与冰山相撞后沉没,在2224名乘客和船员中有1502人死亡。
虽然在幸存的人有一些运气成分在,但确实有些人比其他人有更大的生存机会,如妇女,儿童和上层阶级。
在这个挑战中,我们要求你完成对可能活下来的人进行分析,应用机器学习的工具来预测哪些乘客可以从悲剧中幸存下来。
就是给你训练和测试数据,里面是一些乘客的个人信息以及存活状况,要根据它生成合适的模型并预测其他人的存活状况
数据下载地址:Kaggle_data
使用工具
- python3
- pandas
- jupyter
- sklearn
- seaborn
数据统计
首先导入需要用到的包并读取数据
# 数据分析
import pandas as pd
import numpy as np
import random as rnd
# 可视化
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
# 数据读取
train = pd.read_csv('train.csv', header=0, dtype={'Age': np.float64})
test = pd.read_csv('test.csv', header=0, dtype={'Age': np.float64})
full_data = [train, test]
直接输入数据名(train, test)可以查看表的全部内容,为了避免太长可以选择看前m列数据或后m列数据(用.head(m)或.tail(m),缺省值是5)
train.head(15)
# train.tail(15)
查看属性值
train.columns.values
Out:
array(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype=object)
可以看到共有12列数据
- PassengerId => 乘客ID
- Survived=>存活
- Pclass => 乘客等级(1/2/3等舱位)
- Name => 乘客姓名
- Sex => 性别
- Age => 年龄
- SibSp => 堂兄弟/妹个数
- Parch => 父母与小孩个数
- Ticket => 船票信息
- Fare => 票价
- Cabin => 客舱
- Embarked => 登船港口
查看各个属性有没有缺失值,属性的类型是什么
train.info()
Out:
<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
发现 Age,Cabin有数据缺失了,Cabin数据缺失的还挺多。
从数值方面对各个属性进行大致的统计(总数、平均值、偏差等等)
train.describe()
对非数值的属性进行统计
train.describe(include=['O'])
从上我们可以发现:
- 没有重名的人
- 生还率 是38%左右
- 年龄大致集中在30±15岁
- 男性数目居多,大约占65%(577/891)
- 港口是S的人最多,大约有72%
- 大多数人(>75%)是独自旅行
- …
对数据有了大致的了解后,再对每一个特征深入分析
特征分析
1、Pclass
train[['Pclass', 'Survived']].groupby(['Pclass'], as_index=False).mean()
可以看出,1舱位的人生存率最高
2、Sex
train[["Sex", "Survived"]].groupby(['Sex'], as_index=False).mean()
女性生存几率比男性高多了
3、Family
SibSp 和 Parch 都是 Family ,所以先放到一起统计,之后可能还要细化
for dataset in full_data:
dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1
train[['FamilySize', 'Survived']].groupby(['FamilySize'], as_index=False).mean()
结合我们之前分析的,有超过75%的人是独自旅行,所以我们将FamilySize=1的人归为一类,其他人归为另一类再来看看
for dataset in full_data:
dataset['IsAlone'] = 0
dataset.loc[dataset['FamilySize'] == 1, 'IsAlone'] = 1
train[['IsAlone', 'Survived']].groupby(['IsAlone'], as_index=False).mean()
这就很清楚了,孤身一人的生存率比有家人陪伴的人的生存率要低
4、Age
用图表来分析年龄
grid = sns.FacetGrid(train, col='Survived')
grod.map(plt.hist, 'Age', bins=20)
年龄特别小的(<8)存活率较高,老年人(>50)存活率也有一半左右,大量青壮年牺牲。年龄是一项很重要的特征。
5、Name
我们已经知道数据里没有重名的人,而且我们可以根据称谓来进一步归类乘客的身份,像名字中带有‘Miss’的一般是年轻的女性,带有‘Mrs’的一般是年纪较大的女性,而带有‘Master’的则一般是对未成年男少主人的称呼。数据中有部分人的年龄有缺失,利用名称来模拟年龄也比较合适。
import re
def get_title(name):
title_search = re.search(' ([A-Za-z]+)\.', name)
# If the title exists, extract and return it.
if title_search:
return title_search.group(1)
return ""
for dataset in full_data:
dataset['Title'] = dataset['Name'].apply(get_title)
pd.crosstab(train['Title'], train['Sex'])
for dataset in full_data:
dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col',\
'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss')
dataset['Title'] = dataset['Title'].replace('Ms', 'Miss')
dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')
train[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()
6、Embarked
这一个特征有点奇怪,在哪个港口上船跟上船之后的事情会有什么关系?直觉告诉我这个特征不可信,我们来看数据
fig = plt.figure()
Survived_0 = train.Embarked[train.Survived == 0].value_counts()
Survived_1 = train.Embarked[train.Survived == 1].value_counts()
df=pd.DataFrame({u'Survived':Survived_1, u'Not Survived':Survived_0})
df.plot(kind='bar', stacked=True)
plt.xlabel(u"Embarked")
plt.show()
从C港口上船的人生存率最高,这是巧合还是有某种规律?
7、Fare
最后再分析一下票价,其实我就想知道一点,幸存者是不是普遍比较富有?
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlabel('Survived')
train.groupby('Survived').Fare.mean().plot(kind='bar')
plt.show()
果然如此