泰坦尼克號生存預測——kaggle排名403
選取了來自kaggle的數據集Titanic: Machine Learning from Disaster,利用隨機森林建立模型,預測測試集的乘客在沉船事件中的生存情況。
整個數據分析的過程是:
1.導入數據
2.理解數據
3.數據預處理
4.數據計算&顯示
5.數據建模
6.保存結果
一、導入數據
train <- read.csv(F:/titanic/train.csv,stringsAsFactors = T)ntest <- read.csv(F:/titanic/test.csv,stringsAsFactors = T)nlibrary(dplyr)nfull <- bind_rows(train,test)nView(full)n
查看數據:
二、理解數據
Survived:生存情況,1為存活,0為死亡
Pclass:客艙等級,1為高級,2為中級,3為低級
Name:乘客名字
Sex:乘客性別
Age:乘客年齡
SibSp:在船兄弟姐妹數/配偶數
Parch:在船父母數/子女數
Ticket:船票編號
Fare:船票價格
Cabin:客艙號
Embarked:登船港口
這次的分析目的主要是根據訓練集預測測試集的乘客生存情況,也就是補充test集中缺失的Survived數據。
三、數據預處理
3.1查看是否有缺失值
##查找缺失值nsapply(full,function(x) sum(is.na(x))) 查找數據的NA值nsapply(full,function(x) sum(x==)) 查找數據中的空白值n
結果顯示,survived有418個缺失值,age有263個缺失值,fare有1個缺失值,而Cabin有1024個空白值,Embarked有2個空白值。
其中Survived的缺失值是由於數據的合併造成的,這418個數據是需要我們對測試集做出預測。在這裡我們需要補充Age、Fare和Embarked的缺失值。
3.2補充缺失值
3.2.1補充Embarked數據
先利用下面代碼找出空白值所在位置:
第62和第830位乘客的登船港口數據是空白值。接著提取這兩個乘客的信息,看是否有分析思路:
從上面信息可以知道62號乘客和830號乘客的票價Fare都是80,且Pclass皆是1,那麼是不是可以假設相同票價的乘客是在同一個登船港口登船的呢?
從圖中可以Pclass為1、票價中位數為80的登船港口是「C」,因此我們定義Embarked空白值為「C"。
full$Embarked[c(62,830)] <- Cn
再次查看Embarked是否還有空白值:
到這裡,Embarked的空白值已經補全完整。
3.2.2補充Fare數據
先查找缺失值的位置:
再提取第1044位乘客的信息:
可以看出該乘客是在S登船港口上船,且Pclass為3,由於前面我們補充登船港口的空白值的時候就是利用Fare和Pclass來分析的,因此票價這裡我們可以從相同的思路考慮,提取都是從S登船港口上船且Pclass為3的乘客信息,然後繪圖看是否可以用中位數補充缺失數據。
圖中信息表明相同登船港口和客艙等級的票價大部分分布在0~20中,因此我們可以用中位數補充缺失值。
###對票價缺失的1044乘客補全票價nfull$Fare[1044] <- median(full.fare$Fare,na.rm = T)n
3.2.2補充Age數據
使用MICE預測填補Age的缺失數據:
####設置隨機種子nset.seed(129)n####執行多重插補法,刪除一些沒什麼用的變數nlibrary(mice)nA <- c(PassengerId,Name,Ticket,Cabin,family,Surname,Survived)nmice_mod <- mice(full[,!names(full) %in% A],method = rf)n#####保存完整輸出nmice_output <- complete(mice_mod)n
接著查看使用MICE預測補充的數據跟原來數據趨勢是否有區別:
###繪製年齡分布圖npar(mfrow=c(1,2))nhist(full$Age,freq = F,main = Age:ORiginal Data,col=darkblue,ylim = c(0,0.04))nhist(mice_output$Age,freq = F,main = Age:MICE Output,col = skyblue,ylim = c(0,0.04))n
用MICE預測後填補的數據跟原來的數據趨勢變化不大,也就是說可以用預測後的數據填充Age中的缺失值:
###使用MEIC模型結果替換年齡變數nfull$Age <- mice_output$Agen
最後查看Age和Fare是否還有缺失值:
至此,缺失數據已經補充完整了。
四、數據計算&顯示
這部分主要是從以下幾點分析數據:
1.頭銜對生存率的影響?
2.家庭人數對生存率的影響?
3.性別對生存率的影響?母親身份對生存率的影響?
4.年齡對生存率的影響?兒童身份對生存率的影響?
5.票價對生存率的影響?
4.1分析頭銜對生存率的影響
從列名『Name』中提取中間關於頭銜的欄位,例如『Miss』、『Mrs』等。
###提取頭銜nlibrary(stringr)nfull$Title <- gsub((.*, )|(..*),,full$Name)n
查看頭銜的類別數量:
table(full$Sex,full$Title)n
###將數量較少的頭銜歸類nrare_title <- c(Capt,Col,Don,Dona,Dr,Jonkheer,Lady,Major,Rev,Sir,the Countess)n###重新定義一些稱呼nfull$Title[full$Title==Mlle] <- Missnfull$Title[full$Title==Mme] <- Mrsnfull$Title[full$Title==Ms] <- Missnfull$Title[full$Title %in% rare_title] <- Rare titlen###再次查看頭銜和性別的關係ntable(full$Sex,full$Title)n
對性別、頭銜和生存率的影響情況用ggplot繪製圖分析:
###繪製sex、title和survived的關係圖nlibrary(ggplot2)nggplot(full[1:891,],aes(Title,fill=factor(Survived)))+geom_bar()+facet_grid(.~Sex)+theme_few()+ggtitle(The Survival by Title and Sex)n
從圖中可以得出,頭銜為Miss和Mrs的生存率佔比比較大,而頭銜為Mr的生存率佔比較小。這裡反面驗證了性別對生存率存在一定的影響,為了驗證這點,下面進行性別對生存率的影響分析。
PS:當我採用以下的代碼進行頭銜數據提取時,卻無法對頭銜進行重新編碼歸位,目前還沒有找到答案。
Title <- strsplit(full$Name,split = [,.])nfull$Title <- sapply(Title,[,2)n
4.2分析性別對生存率影響
用馬賽克圖分析性別對生存率的影響:
###性別對存活率的影響nmosaicplot(table(full$Sex,full$Survived),main = Survival By Sex,shade = T)n
圖中顯示,女性存活的佔比更高一點,男性存活的佔比較低。也就是說,當危險發生的時候,女性存活的機會更大一些。那麼如果是一個母親,結果又會是怎樣呢?
需要在數據中新增一個母親的數據,其中滿足母親的要求是:女性,年齡大於18歲,至少有1個小孩:
####生成母親的變數nfull$mother <- Not mothernfull$mother[full$Sex==female&full$Age>18&full$Parch>0&full$Title!=Miss] <- mothern
繪圖查看母親與生存率之間的關係:
####繪製馬賽克圖觀察母親和生存情況的關係圖nmosaicplot(table(full$mother,full$Survived),main = The Survival by Mother,color = c(skyblue,pink))n
在這次的數據中母親的佔比不高,但是生存率卻比非母親的生存率高,說明當一名女性為母親時,會增加她的生存概率。
4.3分析家庭人數對生存率的影響
由於數據中有提到船上兄弟姐妹和父母配偶數,所以,考慮家庭人口對存活率是否有影響呢?
首先,新生成一列家庭人口數的數據:
####家庭人數nfull$familysize <- full$SibSp+full$Parch+1n
接著,提取乘客的姓氏,再生成一個家庭變數,以「姓_家庭人口」的形式存儲數據:
###提取乘客姓氏nfull$Surname <- sapply(strsplit(full$Name,split = [,.]),[,1)n###生成一個家庭變數nfull$family <- paste(full$Surname,full$familysize,sep = _)n
最後,使用ggplot2繪製分析家庭人數與生存情況的關係:
ggplot(full[1:891,],aes(x=familysize,fill=factor(Survived)))+geom_bar(stat = count,position=dodge)+scale_x_continuous(breaks = c(1:11))+labs(x=Family size)+theme_bw()+ggtitle("Family size VS Survived")n
圖中顯示,家庭人口為1和家庭人口大於4人的比較容易死亡,而家庭人口在2至4人中的生存率較高。根據這個發現,我們可以將家庭人口進行分類,分成單身、小家庭和大家庭:
###將上述結果進行合併nfull$Fsize[full$familysize==1] <- singletonnfull$Fsize[full$familysize>1&full$familysize<5] <- small familynfull$Fsize[full$familysize>=5] <- big familyn
同樣畫圖進行分析,看結果是否與上述的情況一致:
###通過繪製馬賽克圖查看家庭規模和生存情況的關係nmosaicplot(table(full$Fsize,full$Survived),main = Family Size by Survival,shade = T)n
同樣是小家庭的生存率較高,因此當初船上的家庭人口數量對生存率有一定的影響。
4.4分析年齡對生存率的影響
根據性別來劃分年齡,繪製圖分析年齡對生存率的影響:
###分析性別和年齡與生存情況的關係nggplot(full[1:891,],aes(Age,fill=factor(Survived)))+geom_histogram()+facet_grid(.~Sex)+theme_few()+ggtitle(The Survival by Age and Sex)n
其中代碼「facet_grid(.~Sex)」即是按年齡劃分的意思。
從圖中可以得出,無論是哪個年齡階段仍然是女性的生存率較高,但是,我們同時也注意到0至20歲這部分,無論是女性還是男性生存率都比較高,那麼是不是可以考慮一下年齡在20歲以下的對生存率的影響呢?參考了其他的案例,決定以18歲作為一個分界點,也就是考慮兒童與成人對生存率的影響。
首先生成一個新數據,劃分「兒童」與「成年人」:
###將年齡層進行劃分成兒童和成人,再觀察和生存情況的關係nfull$child[full$Age < 18] <- childnfull$child[full$Age >= 18] <- adultntable(full$child,full$Survived)n
繪製馬賽克圖分析結果:
####繪製馬賽克圖觀察兒童和生存情況的關係圖nmosaicplot(table(full$child,full$Survived),main = The Survival by Age,shade = T)n
child的生存率比成人的更高,那是不是說明了小女孩的存活率會更高呢?
4.5分析票價對生存率的影響
最後一個是分析票價對生存率是否有影響的分析。為了便於分析,對票價進行了歸類:
##分析票價Fare與生存率的關係nfull$Fare1 <- lownfull$Fare1[full$Fare>=100 & full$Fare <300] <- middlenfull$Fare1[full$Fare>=300] <- hightn
同樣繪製馬賽克圖進行分析:
結果顯示高等票和中等票的生存率更高一些,而低等票的生存率最低。為了更直觀的表示結果,我們可以看看計算出來的數據:
###自定義函數,查看各數據生存率的佔比nrate_survived <- function(n){n full_rate <- xtabs(~n+Survived,data = full)n rate <- prop.table(full_rate,1)n return(rate)n}nrate_survived(full$Fare1)n
計算結果跟圖示的一樣,高等票和中等票的生存率更高一些,特別是高等票的存活率達到了百分百。
到了這裡,數據分析已經結束了,我們知道了頭銜、性別、母親、年齡、小孩、票價等都對生存率有著一定的影響。究竟哪個影響更大,目前尚不知道。
五、數據建模
這部分主要是進行建立模型、因子重要性分析以及測試集數據的預測。
5.1建立模型
模型因子的選擇:在數據分析部分,我們已經知道了頭銜、性別、母親、年齡、小孩、票價以及家庭人口數量等都對生存率有著一定的影響,其中性別和母親屬於重複項,所以只考慮性別這一項,年齡中主要是小孩的因素起決定作用,所以這部分的結果我們主要選擇了頭銜、性別、小孩、票價以及家庭人口數量的影響,而客艙等級和登船港口在某方面決定了我們在船上的位置,所以這兩個也選擇了考慮因子的範圍內。
###拆分訓練集和測試集ntrain <- full[1:891,]ntest <- full[892:1309,]n####模型nlibrary(randomForest)n###設置隨機種子nset.seed(754)n###建立模型nrf_mode <- randomForest(factor(Survived)~Pclass+Fare+Embarked+Title++Sex+Fsize+child,data = train)n###顯示模型誤差nplot(rf_mode,ylim = c(0,0.36))nlegend(topright,colnames(rf_mode$err.rate),col=1:3,fill=1:3)n
顯示模型誤差的這張圖中,我們可以得知死亡的誤差率在0.1左右,而生存的誤差率是0.3左右,也就是說,更容易判斷這個乘客是否死亡。
5.2分析因子重要係數
對因子的重要係數進行分析:
###獲取重要係數nimportance <- importance(rf_mode)nvarImportance <- data.frame(variables=row.names(importance),Importance=round(importance[,MeanDecreaseGini],2))n###對於變數根據重要係數進行排列nlibrary(dplyr)nrankImportance <- varImportance %>% mutate(Ranke= paste0(#,dense_rank(desc(Importance))))n###使用ggplot繪製重要變數相關係圖nggplot(rankImportance,aes(x=reorder(variables,Importance),y=Importance,fill=Importance))+n geom_bar(stat=identity)+n geom_text(aes(x=variables,y=0.5,label=Ranke),hjust=0,vjust=0.55,size=4,colour=red)+n labs(x=Variables)+n coord_flip()+theme_few()+ggtitle(The Importance of Variables)n
結果顯示,佔比前三重要的因子是頭銜、性別、票價。
最後是對測試集進行預測:
###基於測試集進行預測nprediction <- predict(rf_mode,test)n####將結果保存為數據框nsolution <- data.frame(PassengerId=test$PassengerId,Survived=prediction)n
六、保存結果
最後對結果進行保存:
###保存結果nwrite.csv(solution,file=solution,row.names=F)n
總結:這次的結果參考了知乎上的其他小夥伴關於Titanic的分析案例,在學習其他的案例的同時,一邊思考為什麼這麼做,一邊思考這些代碼是代表什麼意思,總共花了一星期才把代碼敲好,上傳到kaggle看排名的時候,一開始1236名,後面進行了模型因子的篩選後,排名為403。
推薦閱讀:
※乾貨 | 這是一份你急需的數據分析的職業規劃
※你值5K還是15K?實戰案例,測測你的分析功力
※七周成為數據分析師:看完後,別再說自己不懂用戶畫像了
※花6000賺48,數據分析師的另一面
※結構思維——用結構化思考讓數據分析到達問題的底層