泰坦尼克號生存率資料集作為一個被徹底研究的物件,是每一個數據分析初學者都必須練習的一項重要內容。廢話不多說了,咱們一項一項開始吧。

理解資料

匯入資料集:

> train<-read。csv(“D:/train。csv”,stringsAsFactors=F)

> test<-read。csv(“D:/test。csv”,stringsAsFactors = F)

可以看到train有891條觀測,test有418條觀測

為避免重複處理資料,故合併兩個資料集一起處理:

> library(dplyr)

> full<-bind_rows(train,test)

檢視資料結構:

> str(full)

‘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 May Peel)” 。。。

$ 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” 。。。

字比較多,但是不要害怕,我們看前兩列就好:-)

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型變數。

檢視缺失值:

> sapply(full,function(X) sum(is。na(X))) #檢視缺失值#

PassengerId Survived Pclass Name Sex Age SibSp

0 418 0 0 0 263 0

Parch Ticket Fare Cabin Embarked

0 0 1 0 0

> sapply(full,function(X) sum(X==“”)) #檢視空值#

PassengerId Survived Pclass Name Sex Age SibSp

0 NA 0 0 0 NA 0

Parch Ticket Fare Cabin Embarked

0 0 NA 1014 2

這裡涉及到sapply的用法:lapply()和sapply()把第一個列表或向量作為其第一個引數,再把需要應用到每個列表元素的函式作為它的第二個引數。其實它也應用到了迴圈,是一種隱式的迴圈,對列表的每一個元素做同樣的函式計算。

特徵工程

探討階層(Pclass)與生存率的關係:

> full$Survived<-as。factor(full$Survived) #先轉換成因子#

> full$Pclass<-as。factor(full$Pclass)

繪圖,從圖中得到我們想要得資訊:

> ggplot(full[(1:891),],aes(x=Pclass,y=。。count。。,fill=Survived))+

+ geom_bar(position =“dodge”)+geom_text(stat=“count”,aes(label=。。count。。),vjust=-0。2,colour=“black”,position=position_dodge(。9),size=5)+labs(title=“社會階層(pclass)對生存率的影響”)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

上層生存率136/80,是死亡人數的1。7倍,中層87/97,是死亡人數的0。89倍,下層死亡率飆升119/372,生存的人數只有死亡人數的三分之一。可以看到階層對生存率的影響還是挺大的。

姓名對生存率的影響

鑑於東西方文化的不同,西方國家姓氏中的title可能對生存率的有影響,所以,從姓名中提取title。

> full$title<-strsplit(ful$Name,“,”)%>%sapply(“[”,2)

> full$title<-strsplit(ful$title,“[。]”)%>%sapply(“[”,1)

> table(full$Sex,full$title)

Capt Col Don Dona Dr Jonkheer Lady Major Master Miss Mlle Mme

female 0 0 0 1 1 0 1 0 0 260 2 1

male 1 4 1 0 7 1 0 2 61 0 0 0

Mr Mrs Ms Rev Sir the Countess

female 0 197 2 0 0 1

male 757 0 0 8 1 0 #目的達到了,?#

然後給title分類,title很重要,會直接影響結果。先合併一些稀有得title

rare_title <- c(‘Dona’, ‘Lady’, ‘the Countess’,‘Capt’, ‘Col’, ‘Don’,

+ ‘Dr’, ‘Major’, ‘Rev’, ‘Sir’, ‘Jonkheer’)

> full$title[full$title==“ Mlle”]<-“Miss”

> full$title[full$title==“ Ms”]<-“Miss”

> full$title[full$title==“ Mme”]<-“Mrs”

> full$title[full$title %in% rare_title]<-“rare_title”

上圖:

ggplot(full[(1:891),],aes(x=title,y=。。count。。,fill=Survived))+geom_bar(position =“dodge”)+geom_text(stat=“count”,aes(label=。。count。。),vjust=-0。2,colour=“black”,position=position_dodge(。9),size=3)+labs(title=“頭銜(Title)對生存率的影響”)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

從圖中可以看到,Mr,得犧牲率非常高,幾乎是生存率得三倍以上,而Miss,Mrs的命運就好很多啦,生存率遠高於死亡率。

性別(Sex)對生存率的影響

ggplot(full[(1:891),],aes(x=Sex,y=。。count。。,fill=Survived))+geom_bar(position =“dodge”)+geom_text(stat=“count”,aes(label=。。count。。),vjust=-0。2,colour=“black”,position=position_dodge(。9),size=5)+labs(title=“性別(Sex)對生存率的影響”)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

完全符合對title的判斷,“女士優先”在西方社會一直被視為最基本的行為準則,這在泰坦尼克上也充分展現出來:74%的女性活了下來,而只有接近19%的男性有幸存活。

年齡(Age)對生存率的影響

> ggplot(data=full[(!is。na(full$Age)) & row(as。matrix(full[,“Age”]))<=891,],aes(x=Age,colour=Survived))+geom_line(stat=“bin”,binwidth=5,na。rm=TRUE)+labs(title=“年齡(Age)對生存率的影響”) #Age中有大量缺失值,此圖是剔除缺失值的樣子#

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

7歲以下孩子生存率遠高於其他年齡段,可見在逃生的過程中年幼的孩子是重點保護物件。

探討兄妹及配偶個數(SibSP)對生存率的影響

full$SibSp<-as。factor(full$SibSp)

ggplot(full[(1:891),],aes(x=SibSp,y=。。count。。,fill=Survived))+geom_bar(position =“dodge”)+geom_text(stat=“count”,aes(label=。。count。。),vjust=-0。2,colour=“black”,position=position_dodge(。9),size=3) +labs(title=“兄妹及配偶數(SibSp)對生存率的影響”)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

父母及子女數(Parch)對生存率的影響

full$Parch<-as。factor(full$Parch)

> ggplot(full[(1:891),],aes(x=Parch,y=。。count。。,fill=Survived))+geom_bar(position =“dodge”)+geom_text(stat=“count”,aes(label=。。count。。),vjust=-0。2,colour=“black”,position=position_dodge(。9),size=3)+labs(title=“父母及子女數(Parch)對生存率的影響”)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

由SibSP 和Parch聯想到家庭規模對生存率的影響,SibSp與Parch都說明,當乘客無親人時,倖存率較低,乘客有少數親人時,倖存率高於50%,而當親人數過高時,倖存率反而降低。在這裡,可以考慮將SibSp與Parch相加,生成新的變數,FamilySize

> full$Parch<-as。numeric(full$Parch) #只有轉換成數值型才能進行加減#

> full$SibSp<-as。numeric(full$SibSp)

> full$familysize<-full$SibSp+full$Parch+1 #+1是為了加上乘客自己#

繪圖:

ggplot(full[(1:891),],aes(x=familysize,y=。。count。。,fill=Survived))+geom_bar(position =“dodge”)+geom_text(stat=“count”,aes(label=。。count。。),vjust=-0。2,colour=“black”,position=position_dodge(。9),size=3)+labs(title=“家庭規模(familysize)對生存率的影響”)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

由圖可見,2-5口人的家庭生存率情況是最好的,過大或者過小的家庭規模存活情況都不好。

船票(Ticket)對生存率的影響

由於船票的重疊率非常低,沒辦法直接拿來進行判斷。但是船票中還是有一部分重複的,我們姑且認為重複的票是大人帶著孩子,或者其他家人。那麼我們將船票有重複的定義為“share“,單獨的定義為”unique“

tick。count<-aggregate(full$Ticket,by=list(full$Ticket),function(x) sum(!is。na(x)))

> full$TicketCount <- apply(full, 1, function(x) tick。count[which(tick。count[, 1] ==x[”Ticket“]),2])

> full$TicketCount <- factor(sapply(full$TicketCount, function(x) ifelse(x > 1,‘Share’, ‘Unique’)))

繪圖:

> ggplot(full[(1:891),],aes(x=TicketCount,y=。。count。。,fill=Survived))+geom_bar(position =”dodge“)+geom_text(stat=”count“,aes(label=。。count。。),vjust=-0。2,colour=”black“,position=position_dodge(。9),size=5)+labs(title=”船票(TicketCount)對生存率的影響“)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

票價(Fare)對生存率的影響:

ggplot(full[(1:891),],aes(x=Fare,colour=Survived))+geom_line(stat=‘bin’,binwidth=5)+labs(title=”票價(Fare)對生存率的影響“)#資料中有一個缺失值,我忽略了#

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

票價越高,生存率越高。

登船口岸(Embarked)對生存率的影響:

ggplot(full[(1:891),],aes(x=Embarked,y=。。count。。,fill=Survived))+geom_bar(position=‘dodge’)+geom_text(stat=‘count’,aes(label=。。count。。),vjust=-0。2,colour=‘black’,size=5,position=position_dodge(。9))+labs(title=”登船口岸(Embarked)對生存率的影響“)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

C倉生存率:93/168,約為55%,Q倉生存率:30/77,約為39%,S倉生存率:約為34%。可見,C倉的乘客生存率最高。

對於Cabin,缺失值太多了…。。總共1309條資料,缺失了1014條。。。

這樣的值即使插補進去也只能降低總體預測的準確性吧?

那麼,接下來,我們就集中處理一下缺失值:)

3 缺失值處理

Age缺失值263個

首先,用多重插補法(mice)來對缺失值進行填補

> library(mice)

> sum(is。na(full$Age))

[1] 263

> imp<-mice(full,seed=123)

> output<-complete(imp)

> full$Age<-output$Age

> sum(is。na(full$Age))

[1] 0

看一下填充前後的效果:

> par(mfrow=c(1,2))

hist(ful$Age,freq=F,col=‘darkblue’,ylim=c(0,0。04))

> hist(output$Age,freq=F,col=‘lightblue’,ylim=c(0,0。04))

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

Fare中的缺失值只有一個,所以用中位數填充:

sum(is。na(full$Fare))

[1] 1

> full$Fare[is。na(full$Fare)]<-median(full$Fare,na。rm=T)

> sum(is。na(full$Fare))

[1] 0

Embarked有兩個空值

是空值,不是NA

> sum(is。na(full$Embarked))

[1] 0

把空值轉成NA值才能進一步處理:

> full$Embarked[fu$Embarked==”“]<-NA

> sum(is。na(full$Embarked))

[1] 2

> full[is。na(full$Embarked),c(”PassengerId“,”Pclass“,”Fare“,”Embarked“)]

PassengerId Pclass Fare Embarked

62 62 1 80

830 830 1 80

現在我們知道缺失的Embarked都屬於Pclass=1,並且Fare=80的,那麼畫圖看一下NA的位置:

ggplot(full[(1:891),],aes(x=Embarked,y=Fare,fill=Pclass))+geom_boxplot()+geom_hline(yintercept =80,colour=”red“,lwd=1,linetype=”dashed“)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

從圖可知缺失值跟c口,Pclass的中位數完全一致,那麼可以推斷缺失值應該為“C“

full$Embarked[is。na(full$Embarked)]<-”C“

4 預測:

分開訓練組和測試組:

train<-full[(1:891),]

> test<-full[(892:1309),]

用隨機森林進行預測:

library(randomForest)

set。seed(754)

> rf_model<-randomForest(Survived~

+Pclass+Sex+Age+Fare+Embarked+title+familysize+TicketCount,data=train)

繪圖顯示模型誤差:

plot(rf_model,ylim=c(0,0。4))

legend(”topright“,colnames(rf_model$err。rate),col=1:3,fill=1:3)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

由圖可知,對死亡率預測的誤差在0。1左右,對生存率的預測誤差在0。3左右。相對對死亡的預測更準確一些。總體誤差在0。2左右

檢視因子重要性:

> importance(rf_model)

MeanDecreaseGini

Pclass 32。061347

Sex 53。922945

Age 42。131608

Fare 53。811564

Embarked 9。370506

title 71。149280

familysize 24。353217

TicketCount 6。569171

新增一個排名變數:

rm<-importance(rf_model)

reimp<-data。frame(var=row。names(rm),importance=round(rm[,”MeanDecreaseGini“],2))

rankimportance<-reimp%>%mutate(rank=(dense_rank(desc(rm))))%>%arrange(rank) #新增排名變數#

> rankimportance

var importance rank

1 title 71。15 1

2 Sex 53。92 2

3 Fare 53。81 3

4 Age 42。13 4

5 Pclass 32。06 5

6 familysize 24。35 6

7 Embarked 9。37 7

8 TicketCount 6。57 8

繪圖:

ggplot(rankimportance,aes(x=reorder(var,importance),y=importance,fill=importance))+geom_bar(stat=”identity“)+geom_text(aes(x = var, y = 0。5, label = rank),hjust=0, vjust=0。55, size = 4, colour = ‘red’)+labs(x=”Variables“)+coord_flip()

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

終於來到預測環節了!

> prediction<-predict(rf_model,test)

> solution<-data。frame(PassengerId=test$PassengerId,Survivied=prediction)

儲存預測結果

> write。csv(solution,”D:\\solution。csv“,row。names=F)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

這樣的結果對不起被我參考過文章的大牛們

5 調優

之前是用多重插補法填補Age中的空缺值,這次我們用經典決策樹(rpart)

> library(rpart)

> age_model<-rpart(Age~Pclass+Sex+SibSp+Parch+Fare+Embarked+title+familysize+TicketCount,data=full[!is。na(full$Age), ], method=‘anova’)

> full$Age[is。na(full$Age)] <- predict(age_model, full[is。na(full$Age), ])

> sum(is。na(full$Age))

[1] 0 #然而對結果的影響並不明顯#

Embarked中缺失值的情況:

> summary(full$Embarked)

C Q S

272 123 914

可以發現S口登船的乘客人數遠高於其他口,所以將缺失的值改為S

full$Embarked[c(62,830)] = ”S“ #對結果影響不明顯#

現在改用決策樹(party)來預測: #對結果影響非常明顯!#

library(party)

library(grid)

> library(mvtnorm)

> library(modeltools)

> library(stats4)

> library(strucchange)

> library(zoo)

> library(sandwich) #鬼知道用個party包為什麼還要帶上這麼多玩意兒#

set。seed(754)

建模:

model <- cforest(as。factor(Survived) ~ Pclass+Sex+Age+Fare+Embarked+title+familysize+TicketCount, data = train, controls=cforest_unbiased(ntree=2000, mtry=3))

預測:

predict。result <- predict(model, test, OOB=TRUE, type = ”response“)

> submit <- data。frame(PassengerId = test$PassengerId, Survived = predict。result)

儲存預測結果:

> write。csv(submit,”D:\\submit1。csv“,row。names=F)

泰坦尼克號生存預測排名4%(R語言)

泰坦尼克號生存預測排名4%(R語言)

直接從16%飆到了4%……

總結:

隨機森林是最近非常火的預測模型,但也不是出處處都好使,還是要視情況進行甄選。作為入門必修的泰坦尼克生存預測,我從中看到了很多大牛們對基本函式爐火純青的使用。不記得視哪位高人說的了,大意是程式碼要越簡潔越好。深以為是。

太高深的東西對小白來說學習起來非常困難,但是能把很平常的函式玩好也絕非易事。

隨機森林還勉強能懂一些,party包就真不懂了,手頭這方面的學習資料非常少,還要慢慢消化,能有4%的戰績全靠對大牛們的模仿,這也說明這麼長時間以來,他們依舊屹立在頂端,只有被模仿而極少被超越。

附文章連結,有興趣的小夥伴可以看看:

https://www。

kaggle。com/mrisdal/expl

oring-survival-on-the-titanic

機器學習(二) 如何做到Kaggle排名前2%

【R語言進行資料探勘】決策樹和隨機森林 - 推酷