學 R 也有一陣子了,一直以來都是在整理自己的資料。這次來嘗試整理別人的資料,先從 Kaggle 上鐵達尼號的資料來試試。
https://www.kaggle.com/c/titanic
由於我不是資料或統計相關科系畢業的人士,過程中也參考了不少網路資料。
http://www.jasongj.com/ml/classification/
以上連結是我主要參考的網站,是鐵達尼資料分析的詳細過程。指令出問題時則是直接去 stackoverflow 找答案。
資料下載下來共有 3 個 csv 檔,分別為 train, test, gender submission。train 是要拿來建立模型的資料,預測 test 資料中乘客的生存,最後以 gender submission 的資料形式提交答案至 Kaggle 上面。
```
train <- read.table("clipboard", header = T, sep = "\t", na.strings = c("", " ", "NA"), quote = "") test <- read.table("clipboard", header = T, sep = "\t", na.strings = c("", " ", "NA"), quote = "") ```
首先是匯入資料,同時將空白資料補上 NA,一直以來我都習慣用複製貼上的方式,不過這樣不太好,以後還是設定一下路徑會比較好。
```
library(ggplot2) library(dplyr) library(ggthemes) library(scales) library(rpart) library(randomForest) library(party) titanic <- bind_rows(train, test) sapply(titanic, function(x) sum(is.na(x))) ```
載入所需要的 package,計算一下那些變數有 NA。
```
titanic$family <- titanic$SibSp + titanic$Parch + 1 ggplot(titanic, aes(family, fill = factor(Survived))) + geom_bar(stat = "count", position = "dodge") + labs(x = "Family size")
titanic$fsize[titanic$family == 1] <- "single" titanic$fsize[titanic$family > 1 & titanic$family < 5] <- "small" titanic$fsize[titanic$family > 4] <- "large" mosaicplot(table(titanic$fsize, titanic$Survived), main = "Family size vs survival") ```
接下來就是逐一檢視每個變數,不過這裡我偷懶,我直接挑選我主觀意識認為會影響存活的變數來分析。
大家庭可能會沒有辦法每個人都登上救生艇,獨身一人可能會沒有人幫忙你逃命。所以將 SibSp 與 Parch 變數合併為 family,圖中可以看到 2-4 人的家庭其存活數比未存活數高,所以再將 family 簡化為 single、small、large 新命名為 fsize。再做成馬賽克圖比較一下,大家庭的存活數會是最低的。
```
titanic[is.na(titanic$Embarked), ] ggplot(titanic, aes(Embarked, Fare, fill = factor(Pclass))) + geom_boxplot() titanic$Embarked[c(62, 830)] <- "C" ```
找出缺失 Embarked 的資料,一般來說票價會與船艙等級或登入港口有關係,所以這邊做了一個盒子圖來看看。缺失的資料只有 2 個並不多,以中位數的方式填補資料空缺,Pclass = 1、Fare = 80 的中位數情況很符合 Embarked = C。
```
titanic[is.na(titanic$Fare), ] titanic$Fare[1044] <- median(titanic[titanic$Pclass == "3" & titanic$Embarked == "S", ]$Fare, na.rm = T) ```
Fare 的缺失值只有一個,同樣以中位數的方式填補空缺。
```
age_model <- rpart(Age ~ Pclass + Sex + SibSp + Parch + Fare + Embarked + fsize, data = titanic[!is.na(titanic$Age), ], method = "anova") titanic$Age[is.na(titanic$Age)] <- predict(age_model, titanic[is.na(titanic$Age), ]) sapply(titanic, function(x) sum(is.na(x))) ```
再來是年齡的部分,由於年齡的缺失較多,不宜使用中位數法來填補空缺。這裡使用 rpart 來推測,變數使用家庭相關的變數以及票價相關的變數。檢查還有哪些缺失值,由於 cabin 的缺失值較多,這裡就直接捨棄不處理。
```
train_complete <- titanic[1:891, ] %>% mutate_if(is.character, as.factor) test_complete <- titanic[892:1309, ] %>% mutate_if(is.character, as.factor) ```
再將檔案分回原本的 train 與 test,將 character 的特性資料轉為 factor,避免跑模型的時候出現錯誤。
```
model <- glm(Survived ~ Pclass+Sex+Age+Fare+Embarked+fsize, data = train_complete, family = binomial(link = "logit")) predict_survival <- predict.glm(model, test_complete, type = "response") survive <- ifelse(predict_survival >= 0.5, 1, 0) ```
這裡使用比較簡單的邏輯斯分析,跑出來的結果在 0.5 以上則認定為存活,將數值改為 1,反之,則改為 0。
```
submit <- data.frame(PassengerId = test_complete$PassengerId, Survived = survive) write.csv(submit, file = "titanic_submit.csv", row.names = F) ```
存檔並將資料格式改為符合 kaggle 要求的樣式,直接將存好的檔案拖曳上去 kaggle 鐵達尼的繳交頁面即可。準確率只有 0.75598,排名 9062 名。
其實很多資料還可以做更進一步的整理,例如姓名與年齡可以再做一些分級處理。分析模型可以採用比較好的 randomforest,還有很多改進的空間。
沒有留言:
張貼留言