You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

380 lines
14 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 探索性数据分析(EDA)
探索性数据分析(EDA)说白了就是通过可视化的方式来看看数据中特征与特征之间,特征与目标之间的潜在关系,看看有什么有用的线索可以挖掘,例如哪些数据是噪声,有哪些特征的相关性比较低,后续可以造出哪些新的特征等。
## 初窥
当然在EDA之前先要加载数据我们不妨先将训练集train.csv读到内存中并看一看。
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
data=pd.read_csv('./Titanic/train.csv')
# 看看data的前5行
data.head()
```
![](../img/32.jpg)
从图中可以看出数据是由 11 个特征和 1 个标签(Survived)组成的。其中各个特征和标签的意义如下:
| 特征 | 意义 |
|---|---|
| Survived | 是否生还1表示是0表示否 |
| PassengerId| 乘客ID|
| Pclass| 船票类型, 总共3种类型1(一等舱)2(二等舱)3(三等舱)|
| Name | 船客姓名|
| Sex | 船客性别femalemale|
| Age|船客年龄|
|SibSp|船客的兄弟姐妹妻子丈夫的数量|
|Parch|船客的父母,孩子的数量|
|Ticket|船票|
|Fare|船客在船上所花的钱|
|Cabin|船客的船舱号|
|Embarked|船客登船的口岸CQS|
了解了数据种各个属性的含义之后,我们可以看看这个数据集中有没有缺失值。
```python
data.isnull().sum()
```
![](../img/33.jpg)
可以看出 AgeCabin 和 Embarked 这三个特征中有缺失值,我们需要处理这些缺失值。怎样处理呢?先不着急,我们可以先看看数据中有哪些信息可以挖掘。
## 有多少人活了下来
我们首先可以看看训练集中有多少人活了下来。
```python
f,ax=plt.subplots(1,2,figsize=(18,8))
# 生还比例饼图
data['Survived'].value_counts().plot.pie(explode=[0,0.1],autopct='%1.1f%%',ax=ax[0],shadow=True)
ax[0].set_title('Survived')
ax[0].set_ylabel('')
# 生还数量直方图
sns.countplot('Survived',data=data,ax=ax[1])
ax[1].set_title('Survived')
plt.show()
```
![](../img/34.jpg)
从图中可以看出泰坦尼克沉船事件中还是凶多吉少的。因为在 891 名船客中,只有约 38% 左右的人幸免于难,那么接下来尝试使用数据集中不同的特征,来看看他们的生还率有多少。其实这样一个过程我们可以看出大概有哪些类型的船客活了下来。
## 性别与生还率的关系
首先,看看不同性别的生还者数量。
```python
data.groupby(['Sex','Survived'])['Survived'].count()
```
![](../img/35.jpg)
看上去好想女性船客的生还率高一些,我们不妨再可视化一下。
```python
f,ax=plt.subplots(1,2,figsize=(18,8))
data[['Sex','Survived']].groupby(['Sex']).mean().plot.bar(ax=ax[0])
ax[0].set_title('Survived vs Sex')
sns.countplot('Sex',hue='Survived',data=data,ax=ax[1])
ax[1].set_title('Sex:Survived vs Dead')
plt.show()
```
![](../img/36.jpg)
从图中可以看出一个比较有趣的现象,船上的男人是比女人多了 200 多人,但是女人生还的人数几乎是男人生还的人数的两倍,女人的存活率约为 75% ,而男人的存活率约为 19% 的样子。所以 Sex 这个特征应该是一个能够很好的区分一个人是否生还的特征。而且对于生还来说,好像是女士优先。
## 船票类型与生还率的关系
船票类型分三个档次,其中 1 为一等舱, 2 为二等舱, 3 为三等舱。既然船舱分三六九等,那么是不是越高级的舱,它的生还率越高呢?
```python
f,ax=plt.subplots(1,2,figsize=(18,8))
data['Pclass'].value_counts().plot.bar(ax=ax[0])
ax[0].set_title('Number Of Passengers By Pclass')
ax[0].set_ylabel('Count')
sns.countplot('Pclass',hue='Survived',data=data,ax=ax[1])
ax[1].set_title('Pclass:Survived vs Dead')
plt.show()
```
![](../img/37.jpg)
虽然说钱不是万能的,但从可视化结果可以看出,一等舱的生还率最高,大于为 63%,二等舱的生还率约为 48% ,而且虽然三等舱的船客人数是最多的,但生还率确是最低的。所以不难看出,金钱地位还是很重要的,也许一等舱周围有比较多的救生设备。
## 上流女性与生还率的关系
从前两次可视化结果可以看出,女性,上流人士成为了是否能够活下来的关键,那么上流女性(两者的结合)的生还率会不会很高呢?
```python
sns.factorplot('Pclass','Survived',hue='Sex',data=data)
plt.show()
```
![](../img/38.jpg)
从这张图可以看出一等舱的女性(上流女性)的生还率非常高!几乎接近了百分之百!而且二等舱和三等舱的女性的生还率也远比男性的生还率高。这也验证了我们的猜测,在沉船后是优先女性和一等舱的船客的。
## 年龄与生还率的关系
首先可以先看一下训练集中船客的年龄的最值和均值。
```python
print('Oldest Passenger was of:',data['Age'].max(),'Years')
print('Youngest Passenger was of:',data['Age'].min(),'Years')
print('Average Age on the ship:',data['Age'].mean(),'Years')
```
![](../img/39.jpg)
年纪最大的是80岁的老爷爷或者老太太最小的是刚出生的小 baby 平均年龄快 30 岁。这个还是符合常理的。接下来我们看看船舱等级,年龄和生还率的关系,以及性别,年龄和生还率的关系。
```python
f,ax=plt.subplots(1,2,figsize=(18,8))
sns.violinplot("Pclass","Age", hue="Survived", data=data,split=True,ax=ax[0])
ax[0].set_title('Pclass and Age vs Survived')
ax[0].set_yticks(range(0,110,10))
sns.violinplot("Sex","Age", hue="Survived", data=data,split=True,ax=ax[1])
ax[1].set_title('Sex and Age vs Survived')
ax[1].set_yticks(range(0,110,10))
plt.show()
```
![](../img/40.jpg)
从可视化结果可以看出:
- 儿童的数量随着船舱等级的增加而增加10 岁以下的小朋友存活率仿佛都还挺高的,跟船舱等级好像没有太大关系。
- 来自一等舱的 20-50 岁的船客的存活率很高,而且对女性的生还率一如既往的高。
- 对于男性来说,年纪越大,生还率越低。
不过我们的年龄是有缺失值的,如果图简单,可以使用平均年龄来填充缺失的年龄。但是这样做并不合适,比如人家只是个 5 岁的小屁孩,但是你把人家强行改成 29 岁显然是不合适的。那有没有能够更加准确地知道缺失的年龄是多少的方法呢?有!我们可以根据姓名来推断缺失的年龄,因为姓名中有很多类似 Mr 或者 Mrs 这样的前缀,所以我们可以根据姓名的前缀来填充缺失的年龄。
## 填充缺失年龄
外国人的姓名和我们中国人的姓名不太一样,一般都会有 Mr 、 Mrs 、Miss 、Dr 等特殊前缀。所以我们可以先提取姓名中的前缀。
```python
data['Initial']=0
for _ in data:
data['Initial']=data.Name.str.extract('([A-Za-z]+)\.')
```
这样我们能够提取出诸如Capt 、Col 、Don 、Lady 、Major 、Sir 等前缀,接着我们可以将这些前缀替换成 Miss 、 Mr 、 Mrs 、 Other 这四个类别,并统计这四个类别的平均年龄。
```python
data['Initial'].replace(['Mlle','Mme','Ms','Dr','Major','Lady','Countess','Jonkheer','Col','Rev','Capt','Sir','Don'],['Miss','Miss','Miss','Mr','Mr','Mrs','Mrs','Other','Other','Other','Mr','Mr','Mr'],inplace=True)
data.groupby('Initial')['Age'].mean()
```
![](../img/41.jpg)
接着可以根据前缀来填充缺失的年龄。
```python
data.loc[(data.Age.isnull())&(data.Initial=='Mr'),'Age']=33
data.loc[(data.Age.isnull())&(data.Initial=='Mrs'),'Age']=36
data.loc[(data.Age.isnull())&(data.Initial=='Miss'),'Age']=22
data.loc[(data.Age.isnull())&(data.Initial=='Other'),'Age']=46
```
填充完缺失值后,可以尝试可视化一下。
```python
f,ax=plt.subplots(1,2,figsize=(20,10))
data[data['Survived']==0].Age.plot.hist(ax=ax[0],bins=20,edgecolor='black',color='red')
ax[0].set_title('Survived= 0')
x1=list(range(0,85,5))
ax[0].set_xticks(x1)
data[data['Survived']==1].Age.plot.hist(ax=ax[1],color='green',bins=20,edgecolor='black')
ax[1].set_title('Survived= 1')
x2=list(range(0,85,5))
ax[1].set_xticks(x2)
plt.show()
```
![](../img/42.jpg)
从图中可以看出 5 岁以下的小屁孩的生还率比较高80 岁的老人活下来了。
```python
sns.factorplot('Pclass','Survived',col='Initial',data=data)
plt.show()
```
![](../img/43.jpg)
嗯,女性和小孩的生还率比较高。
## 登船口岸与生还率的关系
先把口岸和生还率的关系画出来。
```python
sns.factorplot('Embarked','Survived',data=data)
fig=plt.gcf()
fig.set_size_inches(5,3)
plt.show()
```
![](../img/44.jpg)
可以看出从 C 号口岸上船的生还率最高,最低的是 S 号口岸。嗯,好像并没有什么线索,我们可以再深入一点。
```python
f,ax=plt.subplots(2,2,figsize=(20,15))
sns.countplot('Embarked',data=data,ax=ax[0,0])
ax[0,0].set_title('No. Of Passengers Boarded')
sns.countplot('Embarked',hue='Sex',data=data,ax=ax[0,1])
ax[0,1].set_title('Male-Female Split for Embarked')
sns.countplot('Embarked',hue='Survived',data=data,ax=ax[1,0])
ax[1,0].set_title('Embarked vs Survived')
sns.countplot('Embarked',hue='Pclass',data=data,ax=ax[1,1])
ax[1,1].set_title('Embarked vs Pclass')
plt.subplots_adjust(wspace=0.2,hspace=0.5)
plt.show()
```
![](../img/45.jpg)
现在能看出很多信息了:
- 上船人数最多的口岸是 S 号口岸,而且在 S 号口岸上船的人大多数都是三等舱的船客。
- C 号口岸上船的生还率最高,可能大部分 C 口岸上船的人是一等舱和二等舱船客吧。
- 虽然有很多一等舱的土豪们基本上都是在 S 口岸上船的,但是 S 口岸的的生还率最低。这是因为 S 口岸上船的人中有很多都是三等舱的船客。
- Q 号口岸上船的人中有 90% 多都是三等舱的船客。
```python
sns.factorplot('Pclass','Survived',hue='Sex',col='Embarked',data=data)
plt.show()
```
![](../img/46.jpg)
我们可以看出:
- 一等舱和二等舱的女性的生还率几乎为 100% 这与女性是一等舱还是二等舱没啥关系。
- S 号口岸上船并且是三等舱的,不管是男的还是女的,生还率都很低。金钱决定命运。。。
- Q 号口岸上船的男性几乎团灭因为Q 号口岸上船的基本上都是三等舱船客。
## 填充缺失口岸
由于大多数人都是从 S 号口岸上的船,我们可以假设由于人多,所以在 S 口岸登记信息时漏了几位船客,所以不妨用 S 号口岸填充缺失值。
```python
data['Embarked'].fillna('S',inplace=True)
```
## 兄弟姐妹的数量与生还率的关系
```python
f,ax=plt.subplots(1,2,figsize=(20,8))
sns.barplot('SibSp','Survived',data=data,ax=ax[0])
ax[0].set_title('SibSp vs Survived')
sns.factorplot('SibSp','Survived',data=data,ax=ax[1])
ax[1].set_title('SibSp vs Survived')
plt.close(2)
plt.show()
```
![](../img/47.jpg)
从图可以看出,如果一位船客是单独一个人上船旅游,没有兄弟姐妹而且是单身,那么他有大约 34% 的生还率,生还率比较低。如果兄弟姐妹的数量变多,那么生还率还是呈下降趋势的。这其实挺合理的,因为如果是一个家庭在船上的话,可能会设法救他们而不是救自己,这样一来可能谁都救不了。
## 父母的数量与生还率的关系
```python
f,ax=plt.subplots(1,2,figsize=(20,8))
sns.barplot('Parch','Survived',data=data,ax=ax[0])
ax[0].set_title('Parch vs Survived')
sns.factorplot('Parch','Survived',data=data,ax=ax[1])
ax[1].set_title('Parch vs Survived')
plt.close(2)
plt.show()
```
![](../img/48.jpg)
从图上看会发现结果和上面的比较相似,父母在船上的船客有更大的生还机会。而且对于那些在船上有 1-3 个父母的人来说,生还率还是比较高的。
## 花费与生还率的关系
首先,先看一下花费的最值和均值。
```python
print('Highest Fare was:',data['Fare'].max())
print('Lowest Fare was:',data['Fare'].min())
print('Average Fare was:',data['Fare'].mean())
```
![](../img/49.jpg)
惊奇的发现,居然有人可以享受免费豪华邮轮!!!!
```python
f,ax=plt.subplots(1,3,figsize=(20,8))
sns.distplot(data[data['Pclass']==1].Fare,ax=ax[0])
ax[0].set_title('Fares in Pclass 1')
sns.distplot(data[data['Pclass']==2].Fare,ax=ax[1])
ax[1].set_title('Fares in Pclass 2')
sns.distplot(data[data['Pclass']==3].Fare,ax=ax[2])
ax[2].set_title('Fares in Pclass 3')
plt.show()
```
![](../img/50.jpg)
从图中可以看出平均花费其实是二等舱的普遍消费水平,但是三等舱的人数是最多的,而三等舱的人群中花费人数最多的是 10 左右,因此平均 32 的花费是被有钱的大佬给提上去的。
## 简单总结一下
看了这么多特征对于生还的影响,可能有点懵,不妨先简单总结一下根据可视化结果所获得的信息。
- 性别:女性的生还率高
- 船舱等级:越有钱越容易活下来,头等舱的生还率最高,三等舱的生还率最低。
- 年龄10 岁以下的小朋友的存活率比较高15-35 岁的年轻人存活率低。可能年轻人就是炮灰吧。
- 口岸:即使大多数一等舱的船客在 S 号口岸上的船, 但生还率不是最高的。 Q 号口岸的基本上是三等舱的船客。
- 兄弟姐妹父母爱人数量:有 1-2 个兄弟姐妹,配偶在船上,或 1-3 个父母的生还率比较高,独自一人或者一个大家庭都在船上的生还率比较低。
## 特征之间的相关性系数
相关性分为正相关与负相关,正相关指的是:如果特征 A 的数值变大会导致特征 B 的数值变大;负相关指的是:如果特征 A 的数值变小会导致特征 B 的数值变大。通常使用 [-1, 1] 的数值来表示两个特征之间的相关性,这个值称为**相关性系数**。若该系数为 1 那么表示两个特征之间完全正相关,若为 -1 则表示完全负相关,若为 0 则表示两个特征之间没有相关性(线性的)。
如果现在两个特征高度相关或者完全相关,这就意味着这两个特征都包含高度相似的信息,并且信息的差异非常小,所以其中一个特征是多余的。在构建模型时,我们应该尽量消除这种多余的特征,因为这样能减少训练的时间,也可以在某种程度上缓解过拟合。
所以接下来用热力图对相关性系数进行可视化。
```python
sns.heatmap(data.corr(),annot=True,cmap='RdYlGn',linewidths=0.2) #data.corr()-->correlation matrix
fig=plt.gcf()
fig.set_size_inches(10,8)
plt.show()
```
![](../img/51.jpg)
从热力图上可以看出这些特征之间没有太大的相关性,最高的也就 SibSp与Parch值为 0.41 。