Titanic数据分析与可视化

前言:跟Kaggle上大师们做的第一个项目,记录下目前的心得体会,便于后续查阅。

同步转载至个人公众号:R语言学习

同步转载至个人知乎专栏:R语言可视化进阶

泰坦尼克沉船事故已经过去多年,但是关于它的生存预测问题一直是数据分析与建模的经典案例,今天抽空把Chuck Talbert大师做的预测进行简单翻译和再现,并加入个人理解,原文链接:Titanic: A TidyCaret Approach - (0.8086)

开始数据分析与建模之前,我们一起看看Titanic数据集字段介绍:

#PassengerId:乘客ID编号

#Survived:是否存活,0-未存活,1-存活

#Pclass:船舱号,共1,2,3类舱

#Name:乘客姓名

#Sex:乘客性别,Male,Female

#Age:乘客年龄

#SibSp:兄弟姐妹/配偶数量,0~8

#Parch:父母/子女数量,0~6

#Ticket:船票编号

#Fare:票价

#Cabin:舱位编号

#Embarked:登陆口岸,C、Q、S

原数据共12个字段,分为train集和test集.

1、进行数据读入工作,并简要了解数据结构概况

setwd("E:/R/Kaggle/泰坦尼克")
train <- read.csv("train.csv",stringsAsFactors = FALSE)#读取训练数据
dim(train)#查看数据维度(行数x列数)
#[1] 891  12
test <- read.csv("test.csv",stringsAsFactors = FALSE)#读取测试数据
test$Survived <- NA#向test集新增字段Survived并设置为空值
titanicCombo<- rbind(train,test)#合并训练集与测试集
dim(titanicCombo)#查看数据维度(行数x列数)
#[1] 1309   12
str(titanicCombo)#查看合并数据结构
'data.frame':  1309 obs. of  12 variables:
$ PassengerId: int  1 2 3 4 5 6 7 8 9 10 ...
$ Survived   : int  0 1 1 1 0 0 0 0 1 1 ...
$ Pclass     : int  3 1 3 1 3 3 1 3 3 2 ...
$ Name       : chr  "Braund, Mr. Owen Harris""Cumings, Mrs. John Bradley (Florence Briggs Thayer)""Heikkinen, Miss. Laina" "Futrelle, Mrs. Jacques Heath (Lily MayPeel)" ...
$ Sex        : chr "male" "female" "female""female" ...
$ Age        : num  22 38 26 35 35 NA 54 2 27 14 ...
$ SibSp      : int  1 1 0 1 0 0 0 3 0 1 ...
$ Parch      : int  0 0 0 0 0 0 0 1 2 0 ...
$ Ticket     : chr  "A/5 21171" "PC 17599""STON/O2. 3101282" "113803" ...
$ Fare       : num  7.25 71.28 7.92 53.1 8.05 ...
$ Cabin      : chr  "" "C85" """C123" ...
$ Embarked   : chr  "S" "C" "S""S" ...


2、查看数据缺失情况

colSums(is.na(titanicCombo[1:891,]))#计算每列数据缺失个数
# PassengerId    Survived      Pclass        Name         Sex         Age
#          0           0           0           0           0         177
#       SibSp       Parch      Ticket        Fare       Cabin   Embarked
#           0           0           0          0         687           2

#计算每列数据缺失率,值保留3位小数
round(colSums(100*(is.na(titanicCombo[1:891,])/nrow(titanicCombo[1:891,]))),3)
# PassengerId    Survived      Pclass        Name         Sex         Age
#       0.000       0.000       0.000      0.000       0.000      19.865
#       SibSp       Parch      Ticket        Fare       Cabin   Embarked
#       0.000       0.000       0.000       0.000      77.104       0.224


3、数据预处理

将Survived、Pclass、Sex、Embarked 、Cabin等字段转为因子型,且更改Cabin值。

更改原理:如果Cabin为空,即无座乘客,将其Cabin值填充为0,否则填充1。

library(magrittr)#为了使用其中的管道行数%>%
library(plyr)#为了使用mutate()函数
titanicCombo <- titanicCombo %>%
mutate(Survived =as.factor(Survived), Pclass = as.factor(Pclass),
       Sex = as.factor(Sex),Embarked = as.factor(Embarked),
       Cabin =as.factor(ifelse(nchar(Cabin)>0 ,1,0)))

注:mutate()函数用于对已有列进行数据运算并添加为新列与 base包的transform() 相似, 优势在于可以在同一语句中对刚增加的列进行操作;

nchar(Cabin)>0则为有座乘客,nchar用于计算字符串长度。


4、初级可视化,数据探索

4.1观察船舱等级(Pclass)与存活(Survived)是否有关系

library(ggplot2)
g1 <- titanicCombo[1:891,] %>%
ggplot() +
geom_bar(aes(x = Pclass, fill =Survived))
g2 <- titanicCombo[1:891,] %>%
ggplot() +
geom_bar(aes(x = Pclass, fill =Survived), position = "fill")
library(gridExtra)#为使用grid.arrange()函数
grid.arrange(g1,g2,nrow=2)

g1注:绘制柱状图,横轴为船舱等级,按是否存活进行分类填充颜色;titanicCombo[1:891,] %>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数;gggplot默认为计数,统计各个船舱等级存活、未存活频数。

g2注:titanicCombo[1:891,]%>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数;position = "fill"将每个柱状体设置为百分制,显示每个船舱等级下,存活、未存活比例。

其他注:grid.arrange()函数用于多个图形排版,ncol=2表示绘制两列图形,即各个图形按列分布,也可以设置nrow=2,表示图形按行排列。

绘制图形:

结论1:从图形结果可以看出,1等舱存活人数最多且存活比例最高;其次为2等舱,3等舱存活比例最低,随着舱位等级增加,存活率降低。


4.2增加性别字段(Sex),判断性别是否有存活优势

library(stringr)#为使用其中str_c()函数
titanicCombo[1:891,] %>%
ggplot() +
geom_bar(aes(x = Pclass, fill =str_c(Survived,Sex))) +
scale_fill_discrete("Survived| Sex")

注:titanicCombo[1:891,]%>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数。

str_c() 把多个字符串拼接起来,str_c(Survived,Sex)运行结果为0female、0male、1female、1male。

0female表示没有存活的女性人数,0male表示没有存活的男性人数。

1female表示存活的女性人数,1male表示存活的男性人数。

fill = str_c(Survived,Sex)表示按照0female、0male、1female、1male四类进行颜色填充。

scale_fill_discrete("Survived| Sex")用于设置分类型(离散型)数据数据图例名称,具体为0female、0male、1female、1male,discrete意为离散的。

绘制图形:

结论2:可以看出,各个船舱等级中,女性存活人数都比男性高。


4.3将性别(Sex)、船舱等级(Pclass)结合起来看看他们与存活率的关系

titanicCombo[1:891,] %>%
ggplot() +
geom_bar(aes(x = Pclass, fill =Survived), position = "fill") +
facet_wrap(~Sex)

注:titanicCombo[1:891,]%>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数。

position ="fill"表示绘制百分比图。

facet_wrap(~Sex)表示分面,主要用于分类型(离散型)变量,这里按照性别分面,因为只有male、female两种性别,因此会分成两面,且默认为按照列分面,即两个面之间为并列关系。如果facet_wrap(~colname)中colname有多个取值,且我们需要限定最大分面列数为3,可以设置facet_wrap(~colname,ncol=3)。后面还会用到另一个分面函数:facet_grid(),也是用于分类型(离散型)数据分面。

绘制图形:

结论3:女性在各个船舱等级的存活率均高于男性,可见性别与存活与否有较强关系;另外女性船舱等级与存活率之间存在明显关联,船舱等级越高(1为高),存活率越高。男性群体中也显示船舱等级与存活率之间存在明显关联,船舱等级越高(1为高),存活率越高。


4.4增加年龄(Age)字段,判断性别,船舱等级、年龄等3个字段交互情况下生存率如何

titanicCombo[1:891,] %>%
ggplot(aes(x = Age, y = Survived))+
geom_jitter(aes(color = Sex)) +
facet_wrap(~Pclass)
#Warning message:
#Removed 177 rows containing missing values (geom_point).
#ggplot()在绘图时,会自动将涉及字段中存在缺失值的行删除

注:titanicCombo[1:891,]%>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数。

geom_jitter()用于设置抖动点属性,geom_jitter(aes(color= Sex)) 表示抖动点为性别,且不同性别填充不同颜色。设置抖动点可以让原本重叠的点“探出头”来,表示它存在。

facet_wrap(~Pclass)表示按船舱等级分面,共1~3个等级,因此分为3面,并列排列。

绘制图形:

结论4:我们可以看出年龄小于20岁的乘客存活比例明显高于其他年龄段乘客,且女性存活数量、存活比例均明显高于男性,尤其是1、2等舱中,女性存活比例相当高。随着船舱等级降低(1为最高),存活数量、存活比例均在下降。


4.5增加家庭成员数量(FamilySize)因素

绘制散点图,展现不同船舱等级内,不同性别,拥有亲属数量与存活与否的关系

定义:家庭成员数量变量=兄弟姐妹/配偶数量+父母/子女数量

即:FamilySize=SibSp+Parch

titanicCombo[1:891,] %>%
ggplot(aes(x = Age, y = Survived))+
geom_jitter(aes(color =(as.factor(SibSp + Parch)), size = (as.factor(SibSp + Parch)))) +
facet_grid(Pclass~Sex) +scale_color_discrete("FamilySize") +
scale_size_discrete("FamilySize")

注:titanicCombo[1:891,]%>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数。

关于geom_jitter(aes(color= (as.factor(SibSp + Parch)), size = (as.factor(SibSp + Parch))))的注释:

# 1)geom_jitter()用于绘制抖动点图,尽量避免数据点重叠。

#2)SibSp + Parch用于计算家属数量,然后as.factor(SibSp + Parch)将计算的数量值转换为因子型。

#3)color =(as.factor(SibSp + Parch))表示按家属数量分类填充颜色。

#4)size =(as.factor(SibSp + Parch))表示按家属数量分类设置点的大小,家属数量越多,数据点越大。

关于facet_grid(Pclass~Sex)的注释:

#facet_grid()函数会严格按照用户指定的方向分面。facet_grid(.x)表示横向分面横向分面,facet_grid(y.~)表示纵向分面,facet_grid(y~x)表示纵横两个维度的方向进行分面。

#scale_color_discrete("FamilySize")用于修改离散型数据(家属数量)颜色图例的名字为"FamilySize",默认为(as.factor(SibSp + Parch))

#scale_size_discrete("FamilySize")用于修改离散型数据(家属数量)点大小图例的名字为"FamilySize",默认为(as.factor(SibSp +Parch))


题外话:感兴趣的朋友可以试试下面两串代码:

#1)不设置颜色图例和数据点大小图例

titanicCombo[1:891,] %>%
ggplot(aes(x = Age, y = Survived))+
geom_jitter(aes(color =(as.factor(SibSp + Parch)), size = (as.factor(SibSp + Parch)))) +
facet_grid(Pclass~Sex)

#可以看到图例处,名字为(as.factor(SibSp+ Parch)),颜色图例与数据点大小图例是合二为一的状态,只是图例名字美中不足,乍一看不太懂是什么意思。

#2)设置颜色图例名字为"FamilySize",不设置和数据点大小图例名字

titanicCombo[1:891,] %>%
ggplot(aes(x = Age, y = Survived))+
geom_jitter(aes(color =(as.factor(SibSp + Parch)), size = (as.factor(SibSp + Parch)))) +
facet_grid(Pclass~Sex)+scale_color_discrete("FamilySize")

#可见,图形竟然有两个图例!上面的为颜色图例,下面的为数据点大小图例,且数据点大小图例颜色全是黑色,并没有与颜色进行结合,再者数据点大小图例名称为默认的(as.factor(SibSp + Parch)),生涩难懂。

通过以上两组代码对比,我们知道为什么需要同时设置scale_color_discrete("FamilySize") +scale_size_discrete("FamilySize")了吧。


绘制图形:

结论5:不论性别和船舱等级,家属数量在3个及以下的乘客存活率更高;图中还反映出一个特别的现象:第三船舱中,票价在55元以上的男性乘客存活率极低,我们可以细分该群体,看看原因。


4.6绘制家庭成员数量(FamilySize)与存活的关系图

g1 <- titanicCombo[1:891,] %>%
ggplot(aes(x = as.factor(SibSp +Parch))) +
geom_bar(aes(fill =as.factor(SibSp + Parch))) +
labs(x="FamilySize") +
scale_fill_discrete(guide=FALSE)
g2 <-titanicCombo[1:891,] %>%
ggplot(aes(x = as.factor(SibSp +Parch))) +
geom_bar(aes(fill =Survived),position = "fill")+
labs(x="FamilySize") +
scale_fill_discrete()
grid.arrange(g1,g2)

g1注:图g1为家庭成员数量与存活数量的柱状图。

titanicCombo[1:891,]%>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数。

ggplot(aes(x =as.factor(SibSp + Parch)))表示先计算家庭成员数量SibSp + Parch,然后将其因子化as.factor(SibSp +Parch),再将因子化结果赋值给x轴,关于y轴的值,ggplot默认进行计数。

geom_bar(aes(fill =as.factor(SibSp + Parch)))中geom_bar表示绘制柱状图,aes(fill = as.factor(SibSp +Parch))表示按照家庭成员数量进行填充颜色。

labs(x="FamilySize")中labs表示轴标签设置,这里只设置了x轴名字为FamilySize"

scale_fill_discrete(guide=FALSE)中scale_fill_discrete()函数用于设置离散型数据的图例参数,guide=FALSE表示不显示图例。


g2注:图g2为家庭成员数量与存活比例的百分比堆积柱状图。

titanicCombo[1:891,]%>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数。

ggplot(aes(x =as.factor(SibSp + Parch)))表示先计算家庭成员数量SibSp + Parch,然后将其因子化as.factor(SibSp +Parch),再将因子化结果赋值给x轴,关于y轴的值,ggplot默认进行计数。

geom_bar(aes(fill =Survived),position = "fill")中geom_bar表示绘制柱状图,aes(fill =Survived)表示按照是否存活进行分色填充,position = "fill"表示绘制百分比柱状图。

labs(x="FamilySize")中labs表示轴标签设置,这里只设置了x轴名字为FamilySize"

scale_fill_discrete()表示设置离散型数据图例为默认选项,默认为y轴Survived数据。

绘制图形:

结论6:通过绘制g1,得知家庭成员数量在0个的乘客存活数量最多,存活数量随着家庭成员数量的增加在递减。

通过绘制g2,得知家庭成员数量在3个的乘客,存活比例最高,整体而言,家庭成员数量低于3个的乘客存活比例较其他情况高。


4.7观察是否有座位(Cabin)与性别(Sex)、船舱等级(Pclass)的关系

绘制百分比堆积柱状图

titanicCombo[1:891,] %>%
 ggplot(aes(x = Cabin)) +
 geom_bar(aes(fill = Survived),position= "fill") +
 facet_grid(Sex~Pclass)

注:titanicCombo[1:891,]%>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数。

ggplot(aes(x =Cabin)) 表示横轴值为Cabin座位情况,0代表无座位乘客,1代表有座位乘客

geom_bar(aes(fill =Survived),position = "fill")中geom_bar表示绘制柱状图,设置position ="fill",表示百分比模式的柱状图,aes(fill = Survived)表示按照是否存活进行分类颜色填充。

facet_grid(Sex~Pclass)中acet_grid为分面函数,Sex~Pclass表示按照性别和船舱等级组合分面,性别共2个选项,船舱等级有3个选项,因此组合起来共6个情况,分为6面。

绘制图形:

结论7:对于男性群体而言,有座位乘客存活率明显高于无座位乘客,不论船舱等级如何,均呈现该规律。

对于女性群体而言,女性存活率随着船舱等级降低(1为高,3为低),存活率也降低;在第1~2船舱等级中,无座位乘客存活率略高于有座位乘客,在第3船舱中有座位的女性乘客存活率明显高于无座女性乘客。


4.8观察船票价格(Fare)与是否存活(Survived)的关系

titanicCombo[1:891,] %>%
 ggplot(aes(x = Fare, y =Survived)) +
 geom_jitter(aes(color =(as.factor(SibSp + Parch)), size = (as.factor(SibSp + Parch)))) +
 facet_grid(Sex~Pclass, scales ="free") +
scale_color_discrete("FamilySize") +
scale_size_discrete("FamilySize")

注:titanicCombo[1:891,]%>% 表示筛选titanicCombo数据集中前891行数据的所有列,即训练数据集(train),通过管道函数%>%将数据传给后续绘图函数。

ggplot(aes(x =Fare, y = Survived)) 表示横轴为票价,纵轴为是否存活。

geom_jitter(aes(color= (as.factor(SibSp + Parch)), size = (as.factor(SibSp + Parch))))中geom_jitter表示绘制抖动点,以避免数据点重叠,aes(color = (as.factor(SibSp + Parch))中SibSp+ Parch表示计数家庭成员数量,并用as.factor将其转换为因子型数据,最后按照家庭成员数量分类填色;size = (as.factor(SibSp + Parch))表示按照家庭成员数量大小设置抖动点的行状大小;

scale_color_discrete("FamilySize")用于设置离散型数据颜色图例名字为FamilySize;scale_size_discrete("FamilySize") 用于设置离散型数据形状大小图例名字为FamilySize。

绘制图形:

结论8:首先可以看到头等舱(Pclass=1)的票价明显高于2、3等船舱,不论性别差异;1、2、3等舱存活数量相差无几,但是存活比例头等舱明显更高。且3等舱中家庭成员数量在5人及以上的比例更大,大家庭乘客存活率较低。

特殊点:3等船舱中男性乘客,家庭成员数量小于1,且票价高于55元,这个群体,存活率明显高于同为3等船舱的其他男性。


鉴于4.8的结论,我们将3等船舱中男性乘客,家庭成员数量小于1,且票价高于55元的乘客信息单独调出。

library(highr)#为了使用knitr包
library(knitr)#为使用kable函数
possibleGroup <- titanicCombo[1:891,] %>%subset(Pclass==3&Sex=="male"&Fare > 55&(SibSp + Parch)< 1)
knitr::kable(possibleGroup, caption = 'Group of Interest')


| | PassengerId|Survived |Pclass|Name |Sex | Age| SibSp| Parch|Ticket | Fare|Cabin |Embarked |

|:---|-----------:|:--------|:------|:---------------|:----|---:|-----:|-----:|:------|-------:|:-----|:--------|

|75 | 75|1 |3 |Bing, Mr. Lee |male | 32| 0| 0|1601 | 56.4958|0 |S |

|170 | 170|0 |3 |Ling, Mr. Lee |male | 28| 0| 0|1601 | 56.4958|0 |S |

|510 | 510|1 |3 |Lang, Mr. Fang |male | 26| 0| 0|1601 | 56.4958|0 |S |

|644 | 644|1 |3 |Foo, Mr. Choong |male | NA| 0| 0|1601 | 56.4958|0 |S |

|693 | 693|1 |3 |Lam, Mr. Ali |male | NA| 0| 0|1601 | 56.4958|0 |S |

|827 | 827|0 |3 |Lam, Mr. Len |male | NA| 0| 0|1601 | 56.4958|0 |S |

|839 | 839|1 |3 |Chip, Mr. Chang |male | 32| 0| 0|1601 | 56.4958|0 |S |

注:knitr包中的kable函数可以将数据框数据在R中显示为表格样式。调出符合条件的数据共7条,其中仅2位乘客未存活,可见存活比例相对较高。


4.9手动增加各位乘客的Title,观察是否不同Title群体存活率不一致

第1步:手动增加各位乘客的Title

观察原始数据中Name字段,如:Braund, Mr. Owen Harris,我们的目标是提取出字符串"Mr."。

titanicCombo <- titanicCombo %>%
 mutate(Title =str_extract(Name,".[a-z]+\\."), Title = as.factor(Title))

注:mutate()函数用于数据修整,这里向数据新增Title字段,字段内容通过向原有字段Name进行文本截取获得。

在使用str_extract()函数进行文本截取过程中使用了简单的正则表达式".[a-z]+\\."

".[a-z]+\\."注释:

#[a-z]表示匹配26个小写字母。

#[a-z]+表示允许字母重复,即待匹配字符串中存在重复字母时仍会将其匹配处理,如:abbc

#\\.中\\为转义符号,将诸如".","^"这样具有特殊意义的字符视为普通字符串并顺利匹配处理,如:Mr.Kuppler。

#最最重要的是开始的那个小点,.[a-z]+\\.,“.”表示任意一个字符,这样我们才能完整地匹配出真正的Title,感兴趣的朋友可以将第一个点去掉,看看运行结果的不同。

Title =as.factor(Title)表示将新增的字段内容Title因子化。

第2步:绘制各个Title频数统计图

titanicCombo[1:891,] %>%
 group_by(Title) %>%
 summarise(n = n()) %>%
 arrange(desc(n)) %>%
 ggplot() +
 geom_bar(aes(x = reorder(Title,desc(n), FUN = median), y = n, fill = Title),stat = "identity") +
 labs(x = "Title", y ="Count") +
 scale_fill_discrete(guide=FALSE)

1)数据处理部分解释:

group_by(Title):按Title分组。

summarise(n = n()):n()函数用于计数,summarise(n = n()) 对Title分组计数,并将计数结果传递给字段n。

arrange(desc(n)):desc(n)用于对n字段降序排列。

2)绘图部分解释:

geom_bar表示绘制柱状图。

aes()表示对轴进行参数设置。

aes(x =reorder(Title, desc(n), FUN = median), y = n, fill = Title)中x=reorder(Title,desc(n),FUN = median)表示x轴名称显示顺序按照各个Title的频数中位数进行降序排序后显示,y=n表示y的值为分组汇总后各Title的频数统计值,fill=Title表示按照Title分类填充颜色,因此,每个Title颜色将会不一致。

geom_bar(aes(x,y,fill),stat= "identity")中的stat= "identity"表示对样本点做统计的方式为x、y值一一对应,如Title为Mr.的记录对应n=517,因此在绘制柱状图时,柱子的高度会在y=517处。

labs(x = "Title",y = "Count"):labs()函数用于轴标签设置,这里设置了x轴名字为"Title",y轴名字为"Count"。

scale_fill_discrete(guide=FALSE):scale_fill_discrete()函数用于设置分类型(离散型)数据数据图例名称,guide=FALSE表示不显示图例。

至于不显示图例的原因是显而易见的,因为我们已经对每个Title填充一种颜色进行区分,所以无须再添加图例,意义不大。

附:reorder函数详解:

基本格式:reorder(x,y, FUN = mean, ...,)

基本功能:用于对因子型数据进行排序。

原理:根据字段y的均值/中位数/其他统计指标对x进行排序。x为因子型字段,y为数值型字段,FUN = mean表示默认对y进行求均值,也可以设置FUN = median。

绘制图形:

结论9:Title频数排名前四位分别是Mr,Miss,Mrs,Master,剩下的Title数量微乎其微.

4.10我们决定新增一列字段,命名为Title3,用于将Mr,Miss,Mrs,Master以外的其他Title归为"OTHER"
 
 
titanicCombo <- titanicCombo %>% mutate(Title3 =ifelse(str_detect(Title,"Master."),as.character(Title), ifelse(str_detect(Title,"Mr."),as.character(Title), ifelse(str_detect(Title,"Mrs."),as.character(Title), ifelse(str_detect(Title,"Ms."),as.character("Mrs."), ifelse(str_detect(Title,"Miss."),as.character(Title),"OTHER"))))))%>% mutate(Title3 = as.factor(Title3))
注:这里再次用到mutate()函数,mutate()函数用于对已有列进行运算并添加为新列。
在新增字段Title3过程中,使用多个ifelse()函数进行多次判断,如:ifelse(str_detect(Title,"Master."),as.character(Title),ifelse(...))
关于ifelse()函数的结构可以简单解释为:ifelse(条件为真时,运行操作1,否则运行操作2)。
这里我们进行多次判断:
如果原字段Title中包含"Master."字符串,则在新字段Title3中沿用Title字段内容,并用as.character(Title)将其格式设置为字符串类型。
以此类推,检测原字段Title中是否包含"Mr."、"Mrs."、"Ms."、"Miss.",如果是,则过渡给Title3,否则,在Title3相应位置写上"OTHER"。
mutate(Title3 =as.factor(Title3))则在Title3填上内容后,将其格式设置为因子型。
str_detect()函数为stringr包中的字符串处理函数,用于判断字符中是否包含指定字符串
#基本格式:str_detect(string,pattern)
#string为查询对象,pattern 为查找的特定字符,也可以使用正则表达式确实需查找的字符内容。

4.11经过4.10的处理,我们可以来看看现在Title3的分布情况,以及对应的年龄缺失情况
 
 
library(plyr)#为了使用summarise()library(dplyr)#为了使用group_by()函数、arrange()函数tTitles <- titanicCombo %>% group_by(Title3) %>% summarise(n =n(), Age.NA = sum(is.na(Age))) %>% arrange(desc(n))knitr::kable(tTitles, caption = 'Titanic Titles')
#|Title3 | n|Age.NA|
#|:-------|---:|------:|
#|Mr. | 757| 176|
#|Miss. | 260| 50|
#|Mrs. | 199| 28|
#|Master. | 61| 8|
#|OTHER | 32| 1|
注:titanicCombo%>% group_by(Title3)表示对数据集按照Title3字段分组,summarise(n = n(), Age.NA = sum(is.na(Age))) 表示对分组后的数据进行分类汇总,这里进行了两项汇总:
其一是n = n(),表示对分组后的各个Title进行计数,Age.NA = sum(is.na(Age))表示对年龄字段为NA的记录计数,is.na(Age)对年龄字段进行判断,如果是NA则会返回TRUE,否则返回FALSE,然后再sum()求和,在求和函数中,TRUE相当于数值1,FALSE相当于数值0,因此可以求和。
arrange(desc(n))表示对summarise()汇总结果按照字段n降序排列。
knitr::kable(tTitles,caption = 'Titanic Titles') :kable()函数用于在R中将数据显示为表格样式,方便阅读。caption = 'Titanic Titles'表示设置表格标题为'TitanicTitles'。

结论10:从Title分布情况来看,所有数据中(不只是训练集)有757位乘客为先生,260名小姐,199名已婚女士,61名老师,32名其他人员。从各Title年龄缺失情况来看,先生群体数据缺失量达176条,小姐年龄缺失记录为50条,已婚女士年龄数据缺失量为28条,有较明显的递减。

4.12对整体数据集有个把握之后,我们再来细看训练集数据,剔除年龄字段为NA的记录,计算各Title年龄分布情况(最小值、中位数、最大值)
 
 
tTitles2 <- titanicCombo[1:891,] %>% filter(!is.na(Age)) %>% group_by(Title3) %>%summarise(n = n(), MinAge = min(Age), MedianAge = median(Age), MaxAge =max(Age)) %>% arrange(desc(n))knitr::kable(tTitles2, caption = 'Titanic Titles')
#|Title3 | n|MinAge| MedianAge| MaxAge|
#|:-------|---:|------:|---------:|------:|
#|Mr. | 398| 11.00| 30.0| 80|
#|Miss. | 146| 0.75| 21.0| 63|
#|Mrs. | 109| 14.00| 35.0| 63|
#|Master. | 36| 0.42| 3.5| 12|
#|OTHER | 25| 23.00| 45.0| 70|
注:titanicCombo[1:891,]用于选择训练集部分数据。
filter(!is.na(Age))用于进行数据筛选,这里筛选年龄字段为非空数据。
group_by(Title3)表示按Title3字段对训练集中年龄非空的数据分组。
summarise(n = n(),MinAge = min(Age), MedianAge = median(Age), MaxAge = max(Age)) 表示对分组后的数据进行分类汇总。
汇总操作包括n = n()计数、 MinAge = min(Age)求年龄最小值、MedianAge = median(Age)求年龄中位数、MaxAge =max(Age)求年龄最大值。
arrange(desc(n))表示对汇总后的数据按照字段n进行降序排列。
knitr::kable(tTitles2,caption = 'Titanic Titles') :kable()函数用于在R中将数据显示为表格样式,方便阅读。caption = 'Titanic Titles'表示设置表格标题为'TitanicTitles'。

结论11:Mr. Miss. 年龄差距较大,Mrs. 因为是已婚女士,年龄差距相对较小,Master.中年龄最小值为0.42。

4.13通过对各个Title年龄分布情况进行简单统计后,我们发现有年龄信息的Master. 的年龄中位数为 3.5,我们准备用中位数3.5来补全年龄字段值缺失了的Master. 记录
 
 
titanicCombo <- titanicCombo %>% mutate(Age = ifelse(is.na(Age) & as.character(Title3) =="Master.",3.5,Age))
注:mutate()函数用于对已有列进行运算并添加为新列。
ifelse(is.na(Age)& as.character(Title3) == "Master.",3.5,Age)表示如果Age字段为缺失值,并且Title3显示的是Master.,则将Age列用3.5补全,否则,则沿用原来的Age信息。

4.14我们继续数据清理,是否姓氏和年龄一样,存在较大缺失呢?
数据中Name列中的名字格式:Braund, Mr. Owen Harris,逗号前所有字符串为我们需要提取的姓氏,且总是这样,因此可以使用strsplit()函数进行字符拆分。
 
 
titanicCombo$LastName = sapply(strsplit(titanicCombo$Name, ","), `[`, 1)sum(is.na(titanicCombo$LastName))#[1] 0
注:strsplit()函数用于字符串拆分,拆分原理:根据字符串中与指定字符相匹配的字符对字符串进行分割,分割后的内容不包含指定字符,且为列表格式。
#格式:strsplit(x, split,...)
#x为待拆分的字符串
#split为拆分依据
#strsplit(titanicCombo$Name,", ")这里我们用","作为拆分依据,拆分后返回如下列表:
#...
#[[679]]
#[1] "Goodwin" "Mrs. Frederick(Augusta Tyler)"
#[[680]]
#[1] "Cardeza" "Mr. Thomas Drake Martinez"
#...
#可见,一个name被拆分成两部分,我们所需的是姓氏,即第一部分,因此,我们使用sapply(strsplit(titanicCombo$Name, ", "), `[`, 1)来对列表进行姓氏提取。
#sapply()函数详解:
#sapply()用于对向量、列表等类型数据进行分组运算。
#基本格式:sapply(X, FUN,..., simplify = TRUE, ...)
#X为待分组运算原数据,需为列表、向量格式。
#FUN为需要向每组数据运用的函数。
#simplify = TRUE为默认值,函数sapply的返回值将不是一个list,而是一个矩阵。
#这里X=strsplit(titanicCombo$Name,", "),FUN=`[`,表示内容提取,1表示提取内容的第一部分。
结论12:从运行结果来看,姓氏并无缺失。

4.15我们需要转战下一个维度Ticket
我们决定新增一列字段Ticket2,截取船票编号。
#原数据中Ticket字段内容大致为以下格式:
#A/5 21171
#330877
#C.A. 24579
共同规律是最后都以数字结尾,即船票编号。
 
 
titanicCombo <- titanicCombo %>% mutate(Ticket2 =str_extract(Ticket,"[[:digit:]]+$")) %>% mutate(Ticket2 = ifelse(is.na(Ticket2),Ticket,Ticket2))sum(is.na(titanicCombo$Ticket2))#[1] 0
第1步:截取原有字段Ticket中船票编号数字部分
mutate()函数用于对已有列进行数据运算并添加为新列。
Ticket2 =str_extract(Ticket,"[[:digit:]]+$")解析:
str_extract()函数用于对原有字段Ticket进行内容截取,截取过程中再度使用到正则表达式,[:digit:]表示0~9纯数字,$表示以...结尾,[[:digit:]]+$连起来表示以0~9的数字结尾。
采用截取原有字段Ticket数字部分这种方法创建的Ticket2会存在数据缺失情况,具体缺失量可以通过以下小代码计算出来:
aaa= str_extract(titanicCombo$Ticket,"[[:digit:]]+$")
sum(is.na(aaa))
#[1] 4
第2步:处理缺失值
为了解决Ticket2数值缺失问题,我们需要将Ticket2缺失部分沿用原Ticket字段内容
该代码可以实现:mutate(Ticket2 = ifelse(is.na(Ticket2),Ticket,Ticket2))
sum(is.na(titanicCombo$Ticket2))用于最后的检验,查看Ticket2是否还有缺失值,结果为0,说明缺失值已经处理完毕。
至此,数据分析部分及可视化工作已经结束,模型部分后续更新。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值