使用R語(yǔ)言預(yù)測(cè)泰坦尼克號(hào)乘客生存率

導(dǎo)語(yǔ):

1912年4月10日,號(hào)稱 “世界工業(yè)史上的奇跡”的豪華客輪泰坦尼克號(hào)開始了自己的處女航,從英國(guó)的南安普頓出發(fā)駛往美國(guó)紐約,4月14日晚,泰坦尼克號(hào)在北大西洋撞上冰山而傾覆,1502人葬生海底,705人得救。造成了當(dāng)時(shí)在和平時(shí)期最嚴(yán)重的一次航海事故,也是迄今為止最著名的一次海難。38歲的查爾斯·萊特勒是泰坦尼克二副,他是最后一個(gè)從冰冷的海水中被拖上救生船、職位最高的生還者。在他寫的回憶錄中,列舉幾個(gè)讓人震撼的情景:

  • 在第一艘救生艇下水后,我對(duì)甲板上一名姓斯特勞的女人說:你能隨我一起到那只救生艇上去嗎?沒想到她搖了搖頭:不,我想還是呆在船上好。她的丈夫問:你為什么不愿意上救生艇呢?這名女人竟笑著回答:不,我還是陪著你。此后,我再也沒有見到過這對(duì)夫婦...
  • 亞斯特四世(當(dāng)時(shí)世界第一首富)把懷著五個(gè)月身孕的妻子瑪?shù)铝账蜕?號(hào)救生艇后,站在甲板上,帶著他的狗,點(diǎn)燃一根雪茄煙,對(duì)劃向遠(yuǎn)處的小艇最后呼喊:我愛你們!一副默多克曾命令亞斯特上船,被亞斯特憤怒的拒絕:我喜歡最初的說法(保護(hù)弱者)!然后,把唯一的位置讓給三等艙的一個(gè)愛爾蘭婦女......
  • 斯特勞斯是世界第二巨富,美國(guó)梅西百貨公司創(chuàng)始人。他無(wú)論用什么辦法,他的太太羅莎莉始終拒絕上八號(hào)救生艇,她說:多少年來,你去哪我去哪,我會(huì)陪你去你要去的任何地方。八號(hào)艇救生員對(duì)67歲的斯特勞斯先生提議:我保證不會(huì)有人反對(duì)像您這樣的老先生上小艇。斯特勞斯堅(jiān)定地回答:我絕不會(huì)在別的男人之前上救生艇。然后挽著63歲羅莎莉的手臂,一對(duì)老夫婦蹣姍地走到甲板的藤椅上坐下,等待著最后的時(shí)刻...
  • 新婚燕爾的麗德帕絲同丈夫去美國(guó)渡蜜月,她死死抱住丈夫不愿獨(dú)自逃生,丈夫在萬(wàn) 般無(wú)奈中一拳將她打昏,麗德帕絲醒來時(shí),她已在一條海上救生艇上了。此后,她終生未再嫁,以此懷念亡夫...

在這種生死存亡的緊要關(guān)頭,我們常常認(rèn)為社會(huì)等級(jí)越高、影響力越大,公眾認(rèn)可度越高的人物,生存的概率應(yīng)該越大,其次,乘客家庭成員多,成員間的協(xié)作和對(duì)求生的渴望度越高,生存的概率越高。然而,很多時(shí)候,事情產(chǎn)生這樣的結(jié)果的原因并非我們主觀臆測(cè)的那樣,我們需要通過對(duì)真實(shí)數(shù)據(jù)進(jìn)行科學(xué)的分析,才能發(fā)現(xiàn)很多事情并非我們想象的那樣簡(jiǎn)單,事情產(chǎn)生的本質(zhì),往往隱藏在數(shù)據(jù)之中

下面我們就使用R語(yǔ)言根據(jù)已知存活情況的數(shù)據(jù)建立分析模型來預(yù)測(cè)其他一部分乘客的存活情況,其中,訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)均來源于:https://www.kaggle.com/c/titanic
本文的代碼和分析過程除部分修改外主體參考自Megan L. Risdal的文章:https://www.kaggle.com/mrisdal/exploring-survival-on-the-titanic
===========================第二次更新==============================
更新內(nèi)容:添加變量是否可以用于判斷存活預(yù)測(cè)的依據(jù)
1.乘客等級(jí)對(duì)生存率的影響
更新時(shí)間:2017年6月1號(hào)

=================================================================

一.數(shù)據(jù)的導(dǎo)入和查看

#有些包需要安裝,我們專門建立一個(gè)packagemanger.R文件來管理它門,在工程主入口文件中先進(jìn)行編譯后導(dǎo)入進(jìn)行使用

source('D:/R/RStudioWorkspace/titanic_test/utils/packageManager.R',encoding = 'UTF-8')

library(readr) # File read / write
library(ggplot2) # Data visualization
library(ggthemes) # Data visualization
library(scales) # Data visualization
library(plyr)
library(stringr) # String manipulation
library(InformationValue) # IV / WOE calculation
library(MLmetrics) # Mache learning metrics.e.g. Recall, Precision, Accuracy, AUC
library(rpart) # Decision tree utils
library(randomForest) # Random Forest
library(dplyr) # Data manipulation
library(e1071) # SVM
library(Amelia) # Missing value utils
library(party) # Conditional inference trees
library(gbm) # AdaBoost
library(class) # KNN
library(scales)


train <- read.csv('D:/R/RStudioWorkspace/Titanic dataset from Kaggle/train.csv',stringsAsFactors= FALSE)
test <- read.csv('D:/R/RStudioWorkspace/Titanic dataset from Kaggle/test.csv',stringsAsFactors= FALSE)

# 合并兩個(gè)數(shù)據(jù)框,查看相關(guān)變量名稱
total_data <- bind_rows(train,test)
str(total_data)

查看的數(shù)據(jù)結(jié)果如下:

'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" ...
 $ 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" ...

我們觀察到一共有1309條數(shù)據(jù),每一條數(shù)據(jù)有12個(gè)相關(guān)變量

 $ PassengerId: 乘客編號(hào)
 $ Survived   :存活情況(存活:1 ; 死亡:0)
 $ Pclass      : 客場(chǎng)等級(jí)
 $ Name       : 乘客姓名
 $ Sex          : 性別
 $ Age          : 年齡
 $ SibSp      : 同乘的兄弟姐妹/配偶數(shù)
 $ Parch      : 同乘的父母/小孩數(shù)
 $ Ticket      : 船票編號(hào)
 $ Fare        : 船票價(jià)格
 $ Cabin       :客艙號(hào)
 $ Embarked   : 登船港口

二.特征工程

特征工程: 為了達(dá)到預(yù)測(cè)模型性能更佳,不僅要選取最好的算法,還要盡可能的從原始數(shù)據(jù)中獲取更多的信息。挖掘出更好的訓(xùn)練數(shù)據(jù),就是特征工程建立的過程

2.1乘客社會(huì)等級(jí)越高,存活率越高
ggplot(total_data[!is.na(total_data$Survived),],aes(Pclass,fill=as.factor(Survived)))+
  geom_bar(stat = 'count',position = 'dodge')+
  xlab('Pclass')+ylab('Count')+
  ggtitle(' how Pclass impact Survivor')+
  scale_fill_manual(values=c("#FF6600", "#00C5CD")) +
  geom_text(stat = "count", aes(label = ..count..), position=position_dodge(width=1),  vjust=-0.5) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position="bottom")

結(jié)果如下:

不同客艙與乘客生存的關(guān)系

可以看到隨著乘客等級(jí)越低,在同一等級(jí)中的存活率越低,通過定量的計(jì)算Pclass的WOE(全稱是“Weight of Evidence”,即證據(jù)權(quán)重)和IV(Information Value,信息量,一個(gè)變量的IV 是一個(gè)可以定量衡量變量預(yù)測(cè)能力的指標(biāo),類似的指標(biāo)還有信息增益、基尼系數(shù)等等,可以參考這篇博客,詳細(xì)介紹了WOE和IV:http://blog.csdn.net/kevin7658/article/details/50780391)
可以算出Pclass的WOE和IV如下

WOETable(X=factor(total_data$Pclass[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])
IV(X=factor(total_data$Pclass[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])
#[1] 0.5009497
#attr(,"howgood")
#[1] "Highly Predictive"

從結(jié)果可以看出,Pclass的IV為0.5,且“Highly Predictive”,可以將Pclass 作為預(yù)測(cè)模型的特征變量

2.2 乘客頭銜Title 對(duì)生存率的影響

注意到在乘客名字(Name)中,有一個(gè)非常顯著的特點(diǎn):乘客頭銜每個(gè)名字當(dāng)中都包含了具體的稱謂或者說是頭銜,將這部分信息提取出來后可以作為非常有用一個(gè)新變量,可以幫助我們進(jìn)行預(yù)測(cè)。此外也可以用乘客的姓代替家庭,生成家庭變量。

# 從名稱中挖掘
# 從乘客名字中提取頭銜
#R中的grep、grepl、sub、gsub、regexpr、gregexpr等函數(shù)都使用正則表達(dá)式的規(guī)則進(jìn)行匹配。默認(rèn)是egrep的規(guī)則,sub函數(shù)只實(shí)現(xiàn)第一個(gè)位置的替換,gsub函數(shù)實(shí)現(xiàn)全局的替換。
total_data$Title <- gsub('(.*, )|(\\..*)', '', total_data$Name)

# 查看按照性別劃分的頭銜數(shù)量
table(total_data$Sex, total_data$Title)

結(jié)果如下:

         Capt Col Don Dona  Dr Jonkheer Lady Major Master Miss Mlle Mme  Mr Mrs  Ms Rev Sir the Countess
  female    0   0   0    1   1        0    1     0      0  260    2   1   0 197   2   0   0            1
  male      1   4   1    0   7        1    0     2     61    0    0   0 757   0   0   8   1            0

我們發(fā)現(xiàn)頭銜的類別太多,并且好多出現(xiàn)的頻次是很低的,我們可以將這些類別進(jìn)行合并

# 合并低頻頭銜為一類
rare_title <- c('Dona', 'Lady', 'the Countess','Capt', 'Col', 'Don', 
                'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer')

# 重命名稱呼
total_data$Title[total_data$Title == 'Mlle']        <- 'Miss' 
total_data$Title[total_data$Title == 'Ms']          <- 'Miss'
total_data$Title[total_data$Title == 'Mme']         <- 'Mrs' 
total_data$Title[total_data$Title %in% rare_title]  <- 'Rare Title'

# 再次查看按照性別劃分的頭銜數(shù)量
table(total_data$Sex, total_data$Title)

得到如下結(jié)果:

          Master   Miss   Mr    Mrs     Rare Title
  female      0     264    0    198           4
  male       61      0    757     0           25

下面來看看title 對(duì)生存率的影響,同樣的,使用圖形ggplot繪制

ggplot(total_data[!is.na(total_data$Survived),],aes(Title,fill=as.factor(Survived)))+
  geom_bar(stat = 'count',position = 'dodge')+
  ggtitle('how title impact survived')+
  scale_fill_manual(values=c("#FF6600", "#00C5CD")) +
  geom_text(stat = "count", aes(label = ..count..), position=position_dodge(width=1),  vjust=-0.5) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position="bottom")

得到如下結(jié)果

title 對(duì)生存率的影響
#查看Title 對(duì)Survived 的預(yù)測(cè)能力評(píng)估
WOETable(X=factor(total_data$Title[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])
IV(X=factor(total_data$Title[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])

#[1] 1.522418
#attr(,"howgood")
#[1] "Highly Predictive"

我們可以得出結(jié)論,Title 對(duì)survived有很好的預(yù)測(cè)效果,也需要把Title 添加到預(yù)測(cè)模型的特征變量中
最后,從名稱中獲取到姓氏

#sapply()函數(shù):根據(jù)傳入?yún)?shù)規(guī)則重新構(gòu)建一個(gè)合理的數(shù)據(jù)類型返回
total_data$Surname <- sapply(total_data$Name,  function(x) strsplit(x, split = '[,.]')[[1]][1])
2.3女性和小孩幸存概率應(yīng)該更大

作為弱者,女性和小孩在這種時(shí)刻應(yīng)該得到更好的照顧,生存率應(yīng)該會(huì)更高,

#性別對(duì)生存率的影響
ggplot(total_data[!is.na(total_data$Survived),],aes(Sex,fill=as.factor(Survived)))+
  geom_bar(stat = 'count',position = 'dodge')+
  ggtitle('how Sex impact survived')+
  scale_fill_manual(values=c("#FF6600", "#00C5CD")) +
  geom_text(stat = "count", aes(label = ..count..), position=position_dodge(width=1),  vjust=-0.5) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position="bottom")

得到如下結(jié)果:

性別的影響

同理我們可以得到性別的IV值為:1.341681 同樣也是“Highly Predictive”

#年齡對(duì)生存率的影響
#將年齡劃分成2個(gè)階段 
total_data$AgeGroup[total_data$Age < 18] <- 'child'
total_data$AgeGroup[total_data$Age >= 18] <- 'adult'
table(total_data$AgeGroup,total_data$Survived)

ggplot(total_data[!is.na(total_data$Survived),],aes(x= AgeGroup,fill = as.factor(Survived)))+
  geom_bar(stat = 'count',position = 'dodge')+
  ggtitle('how AgeGroup impact survived')+
  scale_fill_manual(values=c("#FF6600", "#00C5CD")) +
  geom_text(stat = "count", aes(label = ..count..), position=position_dodge(width=1),  vjust=-0.5) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position="bottom")

得到如下結(jié)果

年齡對(duì)生存率的影響

暫且不管NA (缺失數(shù)據(jù))的存活情況,我們可以發(fā)現(xiàn),小孩的成活概率是大于50%的
同樣的我們計(jì)算年齡組的IV值

WOETable(X=factor(total_data$AgeGroup[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])
IV(X=factor(total_data$AgeGroup[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])
#[1] 0.05655127
#attr(,"howgood")
#[1] "Somewhat Predictive"

發(fā)現(xiàn)預(yù)測(cè)能力為somewhat Predictive :有些預(yù)測(cè)效果,暫且保留這個(gè)特征變量,到最后預(yù)測(cè)模型中對(duì)比加入和不加入這個(gè)變量對(duì)預(yù)測(cè)結(jié)果的影響大小再做結(jié)論

2.4 配偶及兄弟姐妹數(shù)適中的乘客更易幸存

我們來看看SibSp 這個(gè)變量對(duì)生存率的影響情況

#配偶及兄弟姐妹數(shù)適中的乘客更易幸存

ggplot(total_data[!is.na(total_data$Survived),],aes(x= SibSp,fill = as.factor(Survived)))+
  geom_bar(stat = 'count',position = 'dodge')+
  ggtitle('how sibsp impact survived')+
  scale_fill_manual(values=c("#FF6600", "#00C5CD")) +
  geom_text(stat = "count", aes(label = ..count..), position=position_dodge(width=1),  vjust=-0.5) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position="bottom")

得到如下結(jié)果

配偶及 兄弟姐妹數(shù)對(duì)生存率的影響

我們發(fā)現(xiàn),配偶及兄弟姐妹數(shù)為1 或者2的生存率還是很高的,下面看看SibSp的IV值

WOETable(X=factor(total_data$SibSp[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])
IV(X=factor(total_data$SibSp[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])
#[1] 0.1448994
#attr(,"howgood")
#[1] "Highly Predictive"

高預(yù)測(cè)性,可以作為特征模型的一個(gè)預(yù)測(cè)變量

2.5 家庭成員數(shù)量的影響

既然我們已經(jīng)根據(jù)乘客的名字劃分成一些新的變量,我們可以把它進(jìn)一步做一些新的家庭變量。首先我們要做一個(gè)基于兄弟姐妹/配偶數(shù)量(s)和兒童/父母數(shù)量的家庭規(guī)模變量。


# 創(chuàng)建一個(gè)包含乘客自己的家庭規(guī)模變量
total_data$Fsize <- total_data$SibSp + total_data$Parch + 1

# Create a family variable 
total_data$Family <- paste(total_data$Surname, total_data$Fsize, sep='_')

# 為了直觀顯示,我們可以用ggplot2 畫出家庭成員數(shù)量和生存家庭數(shù)情況的圖形

ggplot(total_data[!is.na(total_data$Survived),],aes(x= Fsize,fill = as.factor(Survived)))+
  geom_bar(stat = 'count',position = 'dodge')+
  ggtitle('how family size impact survived')+
  scale_fill_manual(values=c("#FF6600", "#00C5CD")) +
  geom_text(stat = "count", aes(label = ..count..), position=position_dodge(width=1),  vjust=-0.5) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position="bottom")

結(jié)果如下:

家庭成員數(shù)量和生存數(shù)量的關(guān)系

再來看看家庭成員數(shù)量對(duì)生存率的預(yù)測(cè)值IV

WOETable(X=factor(total_data$Fsize[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])
IV(X=factor(total_data$Fsize[1:nrow(train)]),Y=total_data$Survived[1:nrow(train)])

[1] 0.3497672
attr(,"howgood")
[1] "Highly Predictive"

為高預(yù)測(cè)性

2.6支出船票價(jià)格對(duì)生存率的影響

船票價(jià)格是連續(xù)的,采用ggplot中 geom_line()進(jìn)行模擬顯示

#支出船票價(jià)格對(duì)生存率的影響
ggplot(total_data[1:nrow(train), ], aes(x = Fare, fill= as.factor(Survived),color = Survived)) + 
  geom_line(aes(label=..count..), stat = 'bin', binwidth=10)  + 
  scale_fill_manual(values=c("#FF6600", "#00C5CD")) +
  labs(title = "How Fare impact survivor", x = "Fare", y = "Count", fill = "Survived")

結(jié)果如下

船票價(jià)格對(duì)生存率的影響

觀察藍(lán)色存活數(shù)量的線條,我們可以發(fā)現(xiàn),船票價(jià)格越高,生存率越高,我們?cè)賮砜纯创眱r(jià)格的IV值,結(jié)果為高預(yù)測(cè)性

#[1] 0.6123083
#attr(,"howgood")
#[1] "Highly Predictive"
2.7 客艙位置的影響

可以發(fā)現(xiàn)在乘客客艙變量 passenger cabin 也存在一些有價(jià)值的信息如客艙層數(shù) deck,但是這個(gè)變量的缺失值太多,無(wú)法做出新的有效的變量,暫時(shí)放棄這個(gè)變量的挖掘

三.缺失數(shù)據(jù)的處理

觀察文件中的數(shù)據(jù),我們會(huì)發(fā)現(xiàn)有些乘客的信息參數(shù)并不完整,由于所給的數(shù)據(jù)集并不大,我們不能通過刪除一行或者一列來處理缺失值,因而對(duì)于我們關(guān)注的一些字段參數(shù),我們需要根據(jù)統(tǒng)計(jì)學(xué)的描述數(shù)據(jù)(平均值、中位數(shù)等等)來合理給出缺失值

3.1 列出所有缺失值

我們可以通過函數(shù)查看缺失數(shù)據(jù)的變量在第幾條數(shù)據(jù)出現(xiàn)缺失和總共缺失的個(gè)數(shù)

3.1 年齡的缺失和填補(bǔ)
#統(tǒng)計(jì)年齡的缺失個(gè)數(shù)
age_null_count <- sum(is.na(total_data$Age))
#age_null_count = 263

通常我們會(huì)使用 rpart (recursive partitioning for regression) 包來做缺失值預(yù)測(cè) 在這里我將使用 mice 包進(jìn)行處理。我們先要對(duì)因子變量(factor variables)因子化,然后再進(jìn)行多重插補(bǔ)法。

#統(tǒng)計(jì)年齡的缺失處理
age_null_count <- sum(is.na(total_data$Age))

# 使自變量因子化
factor_vars <- c('PassengerId','Pclass','Sex','Embarked',
                 'Title','Surname','Family','Fsize')
#lapply()返回一個(gè)長(zhǎng)度與X一致的列表,每個(gè)元素為FUN計(jì)算出的結(jié)果,且分別對(duì)應(yīng)到X中的每個(gè)元素。
total_data[factor_vars] <- lapply(total_data[factor_vars],function(x) as.factor(x))

# 設(shè)置隨機(jī)值
set.seed(129)

# 執(zhí)行多重插補(bǔ)法,剔除一些沒什么用的變量:
mice_mod <- mice(total_data[, !names(total_data) %in% c('PassengerId','Name','Ticket','Cabin','Family','Surname','Survived')], method='rf') 
# 保存完成的輸出 
mice_output <- complete(mice_mod)

讓我們來比較一下我們得到的結(jié)果與原來的乘客的年齡分布以確保沒有明顯的偏差

# 繪制直方圖
par(mfrow=c(1,2))
hist(total_data$Age, freq=F, main='Age: Original Data', 
     col='darkgreen', ylim=c(0,0.04))
hist(mice_output$Age, freq=F, main='Age: MICE Output', 
     col='lightgreen', ylim=c(0,0.04))

結(jié)果如下,右邊圖和左邊圖有很高的相似度


所以,我們可以用mice模型的結(jié)果對(duì)原年齡數(shù)據(jù)進(jìn)行替換。

# 用mice模型數(shù)據(jù)替換原始數(shù)據(jù)
full$Age <- mice_output$Age

# 再次查看年齡的缺失值數(shù)據(jù)
sum(is.na(full$Age))
# 0
3.2票價(jià)的缺失處理
#查看票價(jià)的缺失值
getFareNullID <- function(total_data){
  count <- 0
  for(i in 1:nrow(total_data))
    if(is.na(total_data$Fare[i])){
      #打印缺失票價(jià)的具體行數(shù)
      print(i);
      count <- count+1
    }
  
  return(count)
  
}
fare_null_count <- getFareNullID(total_data)
#fare_null_count  = 1

得到票價(jià)缺失個(gè)數(shù)為1 ,缺失行數(shù)為第1044行
查看這一行我們會(huì)發(fā)現(xiàn)

total_data[1044,]
      PassengerId Survived  Pclass       Name    Sex   Age    SibSp Parch Ticket Fare Cabin
1044   1044          NA     3 Storey, Mr. Thomas   male  60.5     0     0   3701   NA      
      Embarked    Title     Surname      Fsize   Family
1044     S           Mr     Storey         1     Storey_1

我們發(fā)現(xiàn)港口和艙位是完整的,我們可以根據(jù)相同的港口和相同的艙位來大致估計(jì)該乘客的票價(jià),我們?nèi)∵@些類似乘客的中位數(shù)來替換缺失的值

#從港口Southampton ('S')出發(fā)的三等艙乘客。 從相同港口出發(fā)且處于相同艙位的乘客數(shù)目
same_farenull <- sum(total_data$Pclass == '3' & total_data$Embarked == 'S')
# 基于出發(fā)港口和客艙等級(jí),替換票價(jià)缺失值
total_data$Fare[1044] <- median(total_data[total_data$Pclass == '3' & total_data$Embarked == 'S', ]$Fare, na.rm = TRUE)

3.3登船港口號(hào)的缺失
#登船港口號(hào)的缺失值函數(shù)
getEmbarkedNullCount <- function(total_data) {
  count0 <- 0
  count <- 0
  for(i in 1:nrow(total_data))
    if(total_data$Embarked[i] == ""){
#可以打印出缺失的所在行數(shù)
      print(i);
      count <- count +1
    } 
  return(count)
}
#登船港口號(hào)的缺失個(gè)數(shù)
embarked_null_count <- getEmbarkedNullCount(total_data)
#embarked_null_count =2

得到登船港口號(hào)缺失的個(gè)數(shù)為2 ,分別為 62 、830,我估計(jì)對(duì)于有相同艙位等級(jí)(passenger class)和票價(jià)(Fare)的乘客也許有著相同的 登船港口位置embarkment .我們可以看到他們支付的票價(jià)分別為: $ 80 和 $ 80 同時(shí)他們的艙位等級(jí)分別是: 1 和 1 . 我們可以用箱線圖繪制出這三者之間關(guān)系圖


從港口 ('C')出發(fā)的頭等艙支付的票價(jià)的中位數(shù)正好為80。因此我們可以放心的把處于頭等艙且票價(jià)在$80的乘客62和830 的出發(fā)港口缺失值替換為'C'

total_data$Embarked[c(62, 830)] <- 'C'

我們基本上完成了重要參數(shù)缺失值的處理,我們的數(shù)據(jù)集變得更加完整了呢,接下來,需要根據(jù)新的數(shù)據(jù)集創(chuàng)建出新的特征工程

四.新特征工程的建立

通過上面缺失值填補(bǔ)的完成,我們?cè)囍谛碌臄?shù)據(jù)集中挖掘出對(duì)乘客的存活有影響的一些因素,根據(jù)文章剛開始的幾段真實(shí)場(chǎng)景預(yù)測(cè),我們考慮在這種災(zāi)難性的時(shí)刻,小孩和老人相對(duì)于青年或者中年人應(yīng)該會(huì)得到更好的照顧,生存的概率應(yīng)該更高,其次,如果你是一位母親,你相比于其他成年女性是否會(huì)有更高的存活可能?其實(shí)我還有一個(gè)想法,那就是乘客的社會(huì)地位或者說階層 和當(dāng)時(shí)的收入水平層次可能對(duì)生存有一定的影響,當(dāng)然這兩個(gè)因素對(duì)于現(xiàn)在的我們來說非常難以獲取,畢竟事情發(fā)生在100多年前,或許當(dāng)時(shí)的政府,也需要很長(zhǎng)時(shí)間才能準(zhǔn)確的獲取到覺大部分人的這些側(cè)面信息。

4.1年齡的劃分

我們考慮將年齡劃分成三個(gè)階段,小于18歲算小孩,18歲及以上至50歲為青壯年,50歲以上為老年人

#將年齡劃分成3個(gè)階段 
total_data$AgeGroup[total_data$Age < 18] <- 'child'
total_data$AgeGroup[total_data$Age >= 18 & total_data$Age <= 50] <- 'young'
total_data$AgeGroup[total_data$Age > 50] <- 'old'

table(total_data$AgeGroup,total_data$Survived)
#得到如下結(jié)果
           0   1
  child   70  63
  old     51  24
  young  428 255

相比于成人,小孩的生存概率接近50%,小孩得到的照顧比成年高的多

4.2是否為母親

我們從性別和頭銜中提煉出一位成年女性是否為一位母親,看看她的生存概率如何

# Adding Mother variable
total_data$IsMother <- 'Not'
total_data$IsMother[total_data$Sex == 'female' & total_data$Parch > 0 & total_data$Age > 18 & total_data$Title != 'Miss'] <- 'Yes'

# Show counts
table(total_data$IsMother, total_data$Survived)
#結(jié)果如下:
       0   1
  Not 534 303
  Yes  15  39

我們發(fā)現(xiàn),如果是一位母親,那么你生存下來的概率高達(dá)70%,之后,我們整合上面兩個(gè)新變量到原數(shù)據(jù)集

# 完成因子化
total_data$AgeGroup  <- factor(total_data$AgeGroup)
total_data$IsMother <- factor(total_data$IsMother)
#mice 包中顯示缺失數(shù)據(jù)的一種模式。
md.pattern(total_data)

五.預(yù)測(cè)

到了最激動(dòng)人心的時(shí)刻了有沒有,前面四個(gè)步驟都是為了預(yù)測(cè)在做前期準(zhǔn)備,如何進(jìn)行預(yù)測(cè)呢?

5.1.拆分測(cè)試和訓(xùn)練數(shù)據(jù)集

#拆分?jǐn)?shù)據(jù)集
train <- total_data[1:891,]
test <- total_data[892:1309,]

5.2 構(gòu)建訓(xùn)練模型

我們使用隨機(jī)森林法則作用于訓(xùn)練數(shù)據(jù)集來構(gòu)建我們需要的預(yù)測(cè)模型

#拆分?jǐn)?shù)據(jù)集
train <- total_data[1:891,]
test <- total_data[892:1309,]

set.seed(754)
# 構(gòu)建預(yù)測(cè)模型
rf_model <- randomForest(factor(Survived) ~ Pclass + Sex + Age + Fare+ Embarked + Title + Fsize,data = train)

交叉驗(yàn)證

一般情況下,應(yīng)該將訓(xùn)練數(shù)據(jù)分為兩部分,一部分用于訓(xùn)練,另一部分用于驗(yàn)證?;蛘呤褂胟-fold交叉驗(yàn)證。本文將所有訓(xùn)練數(shù)據(jù)都用于訓(xùn)練,然后隨機(jī)選取30%數(shù)據(jù)集用于驗(yàn)證。

cv.summarize <- function(data.true, data.predict) {
  print(paste('Recall:', Recall(data.true, data.predict)))
  print(paste('Precision:', Precision(data.true, data.predict)))
  print(paste('Accuracy:', Accuracy(data.predict, data.true)))
  print(paste('AUC:', AUC(data.predict, data.true)))
}
set.seed(415)
cv.test.sample <- sample(1:nrow(train), as.integer(0.3 * nrow(train)), replace = TRUE)
cv.test <- total_data[cv.test.sample,]
cv.prediction <- predict(rf_model, cv.test, OOB=TRUE, type = "response")
cv.summarize(cv.test$Survived, cv.prediction)
#"Recall: 0.982658959537572"
#[1] "Precision: 0.904255319148936"
#[1] "Accuracy: 0.921348314606742"
#[1] "AUC: 0.895584798917722"
5.3 相關(guān)性檢測(cè)

通過隨機(jī)森林中所有決策樹的Gini 計(jì)算出其他變量相對(duì)于生存變量的相關(guān)性排行,我們可以看出那些因素對(duì)生存率影響較大

# 重要性系數(shù)
importance    <- importance(rf_model)
varImportance <- data.frame(Variables = row.names(importance), 
                            Importance = round(importance[ ,'MeanDecreaseGini'],2))

# 創(chuàng)建基于重要性系數(shù)排列的變量
rankImportance <- varImportance %>%
  mutate(Rank = paste0('#',dense_rank(desc(Importance))))

# 使用 ggplot2  繪出重要系數(shù)的排名
ggplot(rankImportance, aes(x = reorder(Variables, Importance), 
                           y = Importance, total_data = Importance)) +
  geom_bar(stat='identity') + 
  geom_text(aes(x = Variables, y = 0.5, label = Rank),
            hjust=0, vjust=0.55, size = 4, colour = 'red') +
  labs(x = 'Variables') +
  coord_flip() + 
  theme_few()

結(jié)果如下:

圖片.png
5.4 預(yù)測(cè)

最后,我們使用訓(xùn)練好的特征模型作用于測(cè)試數(shù)據(jù)上,得到我們的預(yù)測(cè)結(jié)果

prediction <- predict(rf_model, test)
# 保存數(shù)據(jù)結(jié)果passagerId 和survived參數(shù)
solution <- data.frame(PassengerID = test$PassengerId, Survived = prediction)
# 保存到文件
write.csv(solution, file = 'D:/R/RStudioWorkspace/titanic_test/output/predict_Solution.csv', row.names = F)

得到預(yù)測(cè)結(jié)果文件,我們可以上傳到Kaggle,查看自己的排名情況,

圖片.png

第二次預(yù)測(cè)進(jìn)行了特征變量的刪減,刪了 AgeGroup 和 IsMother,SibSp,,我們第一次選擇特征變量的時(shí)候認(rèn)為的小孩、老人和是否為母親 這幾個(gè)特征應(yīng)該有很大的生存幾率,但是結(jié)果并不是這樣,現(xiàn)實(shí)還是比較殘酷!
就先分析到這吧,感謝你的時(shí)間,后面靈感涌現(xiàn)挖掘到新的特征變量再添加到特征工程中,這樣預(yù)測(cè)結(jié)果應(yīng)該會(huì)更加準(zhǔn)確。排名也會(huì)更加靠前,加油!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容