引言
随着2018年飞逝而过,2019悄然到来,我并没有什么太大的起伏去迎接新年,从上一篇博文截止到今天,好像是有接近一礼拜没有更文了,主要是最近正在参加一个建模比赛,导致原计划这两天要写的年终总结一推再推,另外还顺便报了个集训营,那么年终总结。。。So,不如来更新一篇kaggle小项目吧,趁现在还有时间,建模那边已经快到结尾了,年终总结等博客真正搭好的时候作为第一篇好了。虽然最近也并不是很想处理博客,wordpress看花了眼。。。
泰坦尼克号数据介绍与分析
数据介绍
作为当前机器学习最出名的几个入门kaggle项目,背景就无需多做介绍了。本次泰坦尼克号实验总结了实验楼以及相应的几个博客案例,主要侧重于对随机森林的描述,然后加上自己的一些理解,文底表明文章出处,数据出处如下:
https://www.kaggle.com/c/titanic/data
当下载好数据之后,因为数据集并不大,我便直接用excel打开然后观察数据特征以及背景了,数据标签含义如下:
特征label | 解释说明 |
---|---|
PassengerId | 整型变量,标识乘客的ID,递增变量,对预测无帮助 |
Survived | 整型变量,标识该乘客是否幸存。0表示遇难,1表示幸存。将其转换为factor变量比较方便处理 |
Pclass | 整型变量,标识乘客的社会-经济状态,1代表Upper,2代表Middle,3代表Lower |
Name | 字符型变量,除包含姓和名以外,还包含Mr. Mrs. Dr.这样的具有西方文化特点的信息 |
Sex | 字符型变量,标识乘客性别,适合转换为factor类型变量 |
Age | 整型变量,标识乘客年龄,有缺失值 |
SibSp | 整型变量,代表兄弟姐妹及配偶的个数。其中Sib代表Sibling也即兄弟姐妹,Sp代表Spouse也即配偶 |
Parch | 整型变量,代表父母或子女的个数。其中Par代表Parent也即父母,Ch代表Child也即子女 |
Ticket | 字符型变量,代表乘客的船票号 |
Fare | 数值型,代表乘客的船票价 |
Cabin | 字符型,代表乘客所在的舱位,有缺失值 |
Embarked | 字符型,代表乘客登船口岸,适合转换为factor型变量 |
从这里,我们大致了解了关于这份数据的存在形式,于是我们便可以进行python的使用与分析了,在此之前,导入基本我们需要使用的第三方库与数据:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
train = pd.read_csv(r"C:\Users\xuzhenggen\Desktop\files\train.csv")
test = pd.read_csv(r"C:\Users\xuzhenggen\Desktop\files\test.csv")
数据初步分析
当我们导入数据后,往往并不是直接做数据建模,还有太多的数据处理方面的问题等着我们,只有对数据的认识越深,那么后面的特征工程的构建也就越轻松。那么问题就来了,这份数据到底应该怎么处理呢?
我们首先可以看一下在python中数据的表现形式是否和之前在excel中的形式一致,出于运行单元速度以及效率来考虑,考虑用head,代码如下:
train.head() # head参数默认是5个
test.head()
- | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 3 | Braund, Mr. OwenHarris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S |
- | PassengerId | Pclass | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 892 | 3 | 3 | Kelly, Mr. James | male | 34.5 | 0 | 0 | 330911 | 7.8292 | NaN | Q |
由于篇幅考虑,显示一行。我们可以看到大体和我们想的一样,那么我们再来检查一下变量类型:
train.info()
test.info()
看到了数据的变量类型,和上述表格中预想的一致,那么我们便可以针对每个特征的数据结构给它们归一归类了,这也同样有益于我们加深理解数据,除了使后面的计算更方便,更能帮助我们选择合适的图形做可视化,我们可以进一步进行如下分析:
- 离散型特征: 离散型可以理解为一系列相似的样本,具有同样的数值或者名词,在特定范围有规律性的表示,在这个问题中,离散型的变量有:Survived,Sex 和 Embarked。基于序列的有:Pclass
- 连续型特征: 连续型可以说是和离散型相反,呈现的是表面上看起来没有什么规律,没有特定范围,随着样本变化而变化,在这个问题中,连续型的数值特征有:Age,Fare。离散型数值有:SibSp,Parch
- 混合型特征: 在样本中,既不是明确的英文单词,也不是单纯的数值或字母,而是将其混合起来,形成了一种特定的代号,这种往往我们都是需要注意用正则或者用一些我们习惯的方式去处理与修正它。在这个问题中,Ticket是混合了数值型以及字母数值型的数据类型,Cabin是字母数值型数据
- 缺失、异常型特征: 数据样本有缺失值和异常值,这是很常见的问题,这个问题也是后面需要详细说明的。在这个问题中,Ticket是混合了数值型以及字母数值型的数据类型,Cabin是字母数值型数据
对于连续型和离散型特征具体区别,可以看如下链接:
然后我们就可以查看训练数据的具体分布情况:
#通过使用 percentile=[.1, .2, .3, .4, .5, .6, .7, .8, .9, .99] 来查看分布
train.describe(percentiles=[.1, .2, .3, .4, .5, .6, .7, .8, .9, .99])
我们可以从上表知道:
- 死亡率在60%~70%之间,因为Survice这一项从0变成了1
- 船上的父母以及子女数算比较少的,80%左右的人都算是单身或者说和女伴一起,这或许也是后来能让妇女和儿童先逃的一个因素,还是挺佩服他们的
- 船上贫富差距大,可以从Fare一项看出,虽然从Ticket一起看,会发现有团体票一说,但还是有差距的。假如Rose和Jack能获救,不知道可不可能打破世俗,当然,如果那样就不会有凄美爱情,男女主角的名字也会更换了。
大概可以很明确的就如上几点,可能有人还会说Age数量为啥与其它的少?这个问题就是我们如下需要分析的了:
缺失、异常值处理
我们可以统计一下缺失值到底有多少:
data.isnull().sum() #查看 null 值,查看非空使用 notnull()
总共有 891 个游客的数据,177 个 Age 缺失,687 个 Cabin 缺失,2 个 Embarked 缺失。在后面我们需要用不同的方法补充这些数据。
然后,我们查看特征类别分布是否平衡。类别平衡指分类样例不同类别的训练样例数目差别不大。当差别很大时,为类别不平衡。当类别不平衡的时候,例如正反比为 9:1,学习器将所有样本判别为正例的正确率都能达到 0.9。这时候,我们就需要使用 “再缩放”、“欠采样”、“过采样”、“阈值移动” 等方法。我们可以对Survice做图验证:
sns.countplot(x='Survived',data=train) #对不同值的 'Survived' 进行计数并绘图
这个结果说明样本比例还算均衡,也同样应征了上表中说明的幸存者在30%~40%之间,而这组数据本身就少,差距变化不大,我们可以认为是属于类别平衡问题。
接下来,删除无用的特征 PassengerId, Name。
train.drop(['PassengerId','Name'],axis=1,inplace=True) #删除 train['PassengerId','Name'] 两列数据,axis=1 表示删除列,axis=0 表示删除行,inplace=True 原位删除
train.columns
"""
Index(['Survived', 'Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare',
'Cabin', 'Embarked'],
dtype='object')
"""
名字在这里对我来讲并不是很想分析,看了一篇大佬对名字的分析,从分离出他们之间的姓氏,以及名字长度,去推测他们的社会地位,然后再看看是否与存活相关,虽然最后得出来的结果是有点相关性,但我感觉关联并不是很大,太复杂了,一般我是直接删除,删除不了,降维也会把它降掉。
g=sns.heatmap(train[['Survived','SibSp','Parch','Age','Fare','Pclass']].corr(),cmap='RdYlGn',annot=True) #corr() 计算相关系数,cmap 选择 color map,annot=True 显示相关系数
这里我们可以做一个相关系数矩阵图,从理论上来讲,相关系数越大,那么相关系数就越强,这里Fare的颜色较深,相关性较大,其它次之。
缺失值处理:
缺失值有很多种处理方式,从直接剔除,到取平均值、中位数、众数,到线性回归,拉格朗日插值、三次样条插值、极大似然估计、KNN等等,这些都需要视具体情况具体分析,想起上午刚打完的一个建模比赛,通过spss用了KNN和上下四个数取平均,spss自从集成了python环境还是挺好用的,有时间我也可以写一些自己的理解。
上述列举了这么多的方法,那么它们都是什么情况下使用的呢?
- 缺失值过大,比如说已经超过了正常值的1/2,这种就不需要考虑怎么样填补了,留着这个特征反而是加大误差,可以选择剔除
- 缺失值小于1/2的,但出现了连续型缺失,也可以认为是一大段一大段的,这种如果在前面的话,可以不用去考虑,直接作为NaN构成新样本加入样本中,如果是在中间或者后面,根据缺失量,可以考虑用均值或者是线性回归、灰度预测等抢救一下
- 缺失值远小于1/2,并且是非连续的,这里就可以用一些复杂的插值,或者说用前后数的平均,众数都能填补,并且填补完可能会有一些意想不到的效果。
当然以上仅仅是一些我的理解,还是那句话,具体情况具体分析,另外本题没有采取什么缺失值的技巧,运用的是平均值方式去补充,我们首先观察年龄对存活率的变化情况:
Age0=train[(train['Survived']==0)&(train['Age'].notnull())]['Age'] #死亡乘客的 Age 数据
Age1=train[(train['Survived']==1)&(train['Age'].notnull())]['Age'] #生存乘客的 Age 数据
g=sns.kdeplot(Age0,legend=True,shade=True,color='r',label='NotSurvived') #死亡乘客年龄概率分布图, shade=True 设置阴影
g=sns.kdeplot(Age1,legend=True,shade=True,color='b',label='Survived') #生存乘客概率分布图
在前面,我们根据 heatmap构造的相关系数图中,Age 和 SibSp, Parch,Pclass 相关性高,我们再用箱型图直观感受下,以图形 Sex ~ Age,Pclass ~ Age 为例。
g=sns.factorplot(x='Sex',y='Age',data=train,kind='box')
g=sns.factorplot(x='Pclass',y='Age',data=train,kind='box'