Github Code: Jun4871 Github
과거 의사결정 나무 기법을 통해 타이타닉 생존자 예측을 해본 적이 있었는데, 사람마다 분석하는 방식이 전부 다를 수 있고 이것에 대해 추가적인 공부가 더 필요할 것 같아 다른 사람들의 분석과정을 참고하여 분석을 진행해보고자 한다. 이번 타이타닉 생존자 예측에 있어, 3가지 머신러닝 기법을 사용할 것이다.
분석에 필요한 라이브러리를 불러오는 과정이다. 아래 패키지들을 이번 분석에 활용할 것이다.
지정한 데이터를 R로 읽어오는 과정이며, Kaggle에서 받은 train과 test 데이터를 bind_row() 함수로 묶어서 진행할 것이다. (DPLYR 패키지에 내장되어 있다)
train_data = read.csv("Tanic_train.csv", na.strings = "")
test_data = read.csv("Tanic_test.csv", na.strings = "")
full_data <- bind_rows(train_data, test_data)
#write.csv(full_data, file = "test_titanic.csv", row.names = TRUE)head() 함수를 통해 합쳐진 데이터의 6th 행까지 탐색해보고, summary() 함수를 통해 통계적 요약치를 확인해보자.
## PassengerId Survived Pclass Name
## Min. : 1 Min. :0.0000 Min. :1.000 Length:1309
## 1st Qu.: 328 1st Qu.:0.0000 1st Qu.:2.000 Class :character
## Median : 655 Median :0.0000 Median :3.000 Mode :character
## Mean : 655 Mean :0.3838 Mean :2.295
## 3rd Qu.: 982 3rd Qu.:1.0000 3rd Qu.:3.000
## Max. :1309 Max. :1.0000 Max. :3.000
## NA's :418
## Sex Age SibSp Parch
## female:466 Min. : 0.17 Min. :0.0000 Min. :0.000
## male :843 1st Qu.:21.00 1st Qu.:0.0000 1st Qu.:0.000
## Median :28.00 Median :0.0000 Median :0.000
## Mean :29.88 Mean :0.4989 Mean :0.385
## 3rd Qu.:39.00 3rd Qu.:1.0000 3rd Qu.:0.000
## Max. :80.00 Max. :8.0000 Max. :9.000
## NA's :263
## Ticket Fare Cabin Embarked
## Length:1309 Min. : 0.000 Length:1309 C :270
## Class :character 1st Qu.: 7.896 Class :character Q :123
## Mode :character Median : 14.454 Mode :character S :914
## Mean : 33.295 NA's: 2
## 3rd Qu.: 31.275
## Max. :512.329
## NA's :1
우리의 변수 중 일부를 그래프로 그려 그것들이 생존율에 어떤 영향을 미치는지 시각화해보자.
# Survival
g1 <- ggplot(full_data[1:891,], aes(x = factor(Survived), fill = factor(Survived))) +
geom_bar(position = 'dodge') +
scale_x_discrete() +
labs(title = 'Survival on the Titanic', x = "outcome", y = "Count") +
scale_fill_discrete(name = "Outcome", labels = c("Died", "Survived")) +
theme(legend.position = "right") +
theme_classic()
# Sex
g2 <- ggplot(full_data[1:891,], aes(x = factor(Sex), fill = factor(Survived))) +
geom_bar(position = 'dodge') +
scale_x_discrete() +
labs(title = "Survival by Gender", x = "Gender", y = "Rate") +
scale_fill_discrete(name = "Outcome", labels = c("Died", "Survived")) +
theme(legend.position = "right") +
theme_classic()
# Pclass
g3 <- ggplot(full_data[1:891,], aes(x = factor(Pclass), fill = factor(Survived))) +
geom_bar(position = "dodge") +
scale_x_discrete() +
labs(title = "Survival by passenger Class", x = "Passenger Class", y = "Count") +
scale_fill_discrete(name = "Outcome", labels = c("Died", "Survived")) +
theme(legend.position = "right") +
theme_classic()
# Embarkment
g4 <- ggplot(full_data[1:891,], aes(x = factor(Embarked), fill = factor(Survived))) +
geom_bar(position = "dodge") +
theme(legend.position = "right") +
theme_classic()
# Age
g5 <- ggplot(full_data[1:981,]) +
geom_freqpoly(aes(x = Age, color = factor(Survived)), binwidth = 1) +
theme_classic() +
theme(legend.position = "none") +
labs(title = "Survival by Age", x = "Age", y = "Count")
# Fare
g6 <- ggplot(full_data[1:891,]) +
geom_freqpoly(aes( x = Fare, color = factor(Survived)), binwidth = 0.05) +
scale_x_log10() +
theme_classic() +
theme(legend.position = "none") +
labs(title = "Survival by Fare(log10)", x = "Fare(log10)", y ="Count")
grid.arrange(g1,g2,g3,g4,g5,g6, ncol=2)탐색적 데이터 분석을 통해 우리는 다음과 같은 사실을 알 수 있다.
여기서 성별, 승객 등급, 그리고 운임비 변수가 생존과 낮거나 중간정도의 상관관계를 가지고 있음을 알 수 있다. 이것은 생존을 예측하는 데 중요할 수 있다는 것을 의미한다.
새로운 변수들을 생성해서 특징들을 파악해 볼 것이다
Family size 생성을 위해 Sibsp(siblings + spouse) 와 Parch(parents + children) + 1 조합으로 변수를 만들어 특장을 살펴볼 것이다. (개인 고객이 있으므로 + 1을 해줌)
새롭게 만들어진 Family_size 변수가 그래프로 어떻게 표현되는지 확인해보자.
그래프를 보니 2 ~ 4명 가족단위가 생존에 있어 혜택을 받은 것으로 보인다. 반면에 1명이거나 5명 이상 단위의 그룹은 생존에 있어 그 기회가 적었음을 확인할 수 있다. 이러한 구분을 보여주는 새로운 변수를 만들어 예측모델의 성능을 향상시킬 수 있는 가능성을 보자.
# Create categories for family size : 1, 2-4, 5+
full_data$family_size_range = cut(full_data$family_size, c(0, 1, 4, 15), include.lowest = TRUE)
# 그 다음, 변수의 이름을 수정하자
levels(full_data$family_size_range) = c("1", "2-4", "5+")그래프를 통해 Family_size 변수와 비교했을 때 어떨지 확인해보자.
여기서 우리는 조금 더 확실하게 2~4명 단위의 승객의 생존률이 한 명이나 다섯명 단위 승객의 생존률 보다 높음을 알 수 있다.
계속해서 두 번째 변수인 Title 을 만들어보자. 기존의 변수 ‘이름’ 변수에서 타이틀 정보를 추출할 것이다. 이 변수가 생존을 예측하는데 유용한 정보를 제공하기를 바라며, 정규식 표현을 사용하여 Title 을 추출해보자.
Title의 테이블을 한 번 살펴보도록 하자.
##
## Capt Col Don Dona Dr Jonkheer
## 1 4 1 1 8 1
## Lady Major Master Miss Mlle Mme
## 1 2 61 260 2 1
## Mr Mrs Ms Rev Sir the Countess
## 757 197 2 8 1 1
몇몇 직함들은 거의 없는 것이나 다름이 없었기 때문에 이것들을 새로운 카테고리인 rare_title에 재할당할 것이다.
rare_title = c("Capt","Col","Don","Jonkheer","Lady","Major","Rev","Sir","the Countess","Dr")
full_data$Title[full_data$Title %in% rare_title] <- "Rare title"적당한 카테고리에 재할당해주자.
full_data$Title[full_data$Title=='Mlle'] <- 'Miss'
full_data$Title[full_data$Title=='Ms'] <- 'Miss'
full_data$Title[full_data$Title=='Dona'] <- 'Miss'
full_data$Title[full_data$Title=='Mme'] <- 'Mrs'그래프화해서 직함이 생존률에 어떤 영향을 끼치는지 보자.
이 그래프에서 우리는 Miss 와 Mrs 호칭을 가진 사람들의 생존률이 가장 높은 것을 확인할 수 있다. 여성들 사이에서 생존률이 높았기 때문에 예상과 일치하는 결과라고 볼 수 있다. 또 Maser 호칭을 가진 사람들 또한 생존률이 높았다. 이 그래프에서 Mr호칭은 죽음에 대한 확실한 경향을 보여주고 있다.
여기서는 cabin letter 를 Cabin 컬럼에서 추출하여, 새로운 Cabin_letter 라는 컬럼을 생성할 것이다.
정규식 표현을 사용하여 cabin letter을 추출해보자.
어떤 선실들은 적은 데이터를 가지고 있고, 어떤 선실들은 두 개의 선실로 분류된다. 우리는 이것들을 결합하여 EFGT라고 명명하여 새로운 이름을 만들 것이다. 그리고 기내 문자가 없는 것을 “빈칸”으로 리코딩할 것이다.
full_data$Cabin_letter[full_data$Cabin_letter == "E"] <- "EFGT"
full_data$Cabin_letter[full_data$Cabin_letter == "F"] <- "EFGT"
full_data$Cabin_letter[full_data$Cabin_letter == "F E"] <- "EFGT"
full_data$Cabin_letter[full_data$Cabin_letter == "F G"] <- "EFGT"
full_data$Cabin_letter[full_data$Cabin_letter == "G"] <- "EFGT"
full_data$Cabin_letter[full_data$Cabin_letter == "T"] <- "EFGT"
full_data$Cabin_letter[is.na(full_data$Cabin_letter)] <- "Blank"Cabin_letter 가 생존에 어떠한 영향을 미치는지 그래프로 확인해보자.
그래프를 보고나니, Cabin 을 가진 사람의 생존률이 높고 그러지 못한 사람은 생존률이 떨어지다는 것을 알 수 있었다. 조금 더 자세히 보도록 하자.
full_data$cabin_presence[full_data$Cabin_letter == "Blank"] <- "No cabin"
full_data$cabin_presence[is.na(full_data$cabin_presence)] <- "Cabin"다시 그래프를 띄워보자.
역시 cabin 을 배정받은 사람의 생존률이 더 높았다.
정규표현식을 사용하여 숫자데이터가 아닌 것은 전부 제거하여 Ticket에서 Ticket_number 를 추출할 것이다.
티켓 번호에서 모든 글자를 삭제하는 과정에서 일부 글자는 공백("") 그들 중 몇 명이 비어 있는지 보고 그들에게 값을 재할당하자.
##
## FALSE TRUE
## 1305 4
티켓번호 log 를 그래프화 해보자.
full_data$Ticket_number <- as.integer(full_data$Ticket_number)
ggplot(full_data[1:891,]) +
geom_freqpoly(aes(x = Ticket_number, color = factor(Survived)), binwidth=0.1) +
scale_x_log10() +
scale_color_discrete(name = 'Outcome', labels = c('Died', 'Survived')) +
theme_classic() +
labs(title = 'Survival by Ticket number', x = 'Ticket number', y = 'Count')티켓 번호와 생존 사이에 명확한 추세가 보이지 않는다. 두 변수의 상관관계를 확인해보자.
## [1] -0.01561505
여기에는 실질적인 상관관계가 없는 것 같으니, 티켓 번호 변수를 예측 모델에서 제외시키도록 한다.
Missing Value를 수정하기에 앞서 데이터를 준비해보자.
첫째, 데이터 세트에서 하위 집합을 만들고 나중에 예측을 위해 유지하고자 하는 관련 변수만 포함할 것이다.
각 변수가 숫자형과 팩터형에 맞게 분류되었는지 확인해보자.
full_data_relevant$Survived <- as.factor(full_data_relevant$Survived)
full_data_relevant$Pclass <- factor(full_data_relevant$Pclass, ordered = TRUE)
full_data_relevant$Survived <- as.factor(full_data_relevant$Survived)
full_data_relevant$Title <- as.factor(full_data_relevant$Title)
full_data_relevant$cabin_presence <-as.factor(full_data_relevant$cabin_presence)우리는 이제 Fare 와 Age 에 대한 우리의 누락된 값을 처리할 것이다. 데이터에서 누락된 값이 무엇인지 확인하는 것부터 알아보자. 여기에 VIM 패키지의 aggr()를 사용할 것이다.
##
## Variables sorted by number of missings:
## Variable Count
## Survived 418
## Age 263
## Fare 1
## Pclass 0
## Sex 0
## Title 0
## cabin_presence 0
## family_size_range 0
이제 "preProcess() 기능을 사용하여 누락된 값 모델을 nnImpute로 사전에 처리하겠다. 이렇게 하면 데이터가 확장된다. 우리는 생존 변수를 사전 프로세스 모델에서 제외시킨 후 나중에 다시 추가할 것이다.
md_prediction <- preProcess(full_data_relevant[c(2:8)], method = c( "knnImpute", "center", "scale"))
print(md_prediction)## Created from 1045 samples and 7 variables
##
## Pre-processing:
## - centered (3)
## - ignored (4)
## - 5 nearest neighbor imputation (3)
## - scaled (3)
이제, 우리는 우리가 만든 모델을 사용하여 지속적인 우리의 결측치, 즉 페어와 에이지를 예측할 것이다. 우리는 나중에 착수할 NA를 계산할 것이다.
전에 만든 모델을 사용하여 잔존하는 missing value를 예측할 것이다. 즉 Fare 와 Age 가 되겠다. 그리고 embarked later 에 대한 NA 값을 계산할 것이다.
이제 데이터 프레임에 ’Survived’를 다시 추가하고, full_data_complete 와 full_data의 변수들을 새로운 데이터 프레임으로 만들어보자.
full_data_final <- data.frame(full_data_complete, full_data$Survived)
full_data_final <- cbind(full_data$PassengerId, full_data_final)‘full_data.Survived’ 컬럼이름을 다시 ’Survived’로 명명하고 새로운 데이터 프레임을 만든다.
full_data_final <- rename(full_data_final, Survived = full_data.Survived, PassengerId = "full_data$PassengerId")
full_data_final$Survived <- as.factor(full_data_final$Survived)데이터 모델링을 시작하기 전에 데이터 셋을 train 및 test 데이터로 분할하자.
이제 타이타닉에서 생존을 예측할 수 있는 예측 모델을 만들어보자. 우리가 사용할 첫번째 분류 알고리즘은 랜덤 포리스트이다.
CARET 패키지의 train() 기능을 활용하여 training model을 만들 것이다.
set.seed(222) # Set a random seed
rf_model <- train(Survived ~ .,
method = "rf",
data = train); print(rf_model)## Random Forest
##
## 891 samples
## 8 predictor
## 2 classes: '0', '1'
##
## No pre-processing
## Resampling: Bootstrapped (25 reps)
## Summary of sample sizes: 891, 891, 891, 891, 891, 891, ...
## Resampling results across tuning parameters:
##
## mtry Accuracy Kappa
## 2 0.8289915 0.6307177
## 7 0.8217978 0.6163333
## 13 0.8080451 0.5866530
##
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 2.
혼동행렬을 사용하여 방금 만든 랜덤포레스트 모델의 점검해보자. 이것은 우리에게 우리의 모델의 예상 전반적인 정확성 뿐만 아니라 뿐만 아니라 죽음과 생존예측에 대한 정확성을 알 수 있다.
## Bootstrapped (25 reps) Confusion Matrix
##
## (entries are percentual average cell counts across resamples)
##
## Reference
## Prediction 0 1
## 0 55.1 10.5
## 1 6.6 27.8
##
## Accuracy (average) : 0.8288
우리의 예측에 모델 오차율을 표시한다.
# Create data frame of error rate
rf_err_model <- as.data.frame(rf_model[["finalModel"]][["err.rate"]])
rf_err_model$sequence <- seq(1:500)
# Rename 0's to Died and 1's to Survived
rf_err_model <- rename(rf_err_model, Died ="0", Survived ="1")
# Convert data frame into long format
rf_err_model <- melt(rf_err_model, id = "sequence")
# Plot error rate
ggplot(rf_err_model, aes(x = sequence, y = value, color = variable)) +
geom_line() +
scale_colour_manual(values = c("black", "red2", "forestgreen")) +
theme_classic() +
labs(title = "Error rate in prediction", x = "Sequence", y = "Error rate")여기서 우리는 우리의 전반적인 예측에 대한 오류율과 죽음과 생존에 대한 오류율을 별도로 볼 수 있다. 흥미롭게도, 우리는 생존보다 더 정확하게 죽음을 예측하고 있다.
우리의 예측에서 각 변수의 중요성을 시각화하는 플롯을 만들자.
rf_imprtance <- varImp(rf_model)
ggplot(rf_imprtance, aes(x = reorder(variable, importance), y = importance)) +
geom_bar(stat = "identity") +
labs(title = "Importance of predictors", x = "Predictors", y = "Importance") +
theme_light()이제 랜덤 포레스트 모델을 만들었으니, test 데이터 세트에서 생존을 예측하는 데 사용할 것이다.
테스트 셋을 사용하여 예측해보자.
solution_rf를 PeakerId 및 Surved라는 두 개의 데이터가 있는 데이터 프레임에 저장하자.
파일로 저장하자.
랜덤 포레스트 정확도 : 0.8288
로지스틱 회귀를 사용하여 분류를 시도해보자. 새 오브젝트를 10개 변수에 맞춰 생성하고, 이것을 train 모델에 사용할 것이다.
예측 모델을 train으로 만들고, 모델에 옵션 값을 지정해주자.
set.seed(222) # Set random seed
lr_model <- train(factor(Survived) ~ .,
data = train,
method = "glm",
family = binomial(),
trControl = fitControl) ; print(lr_model)## Generalized Linear Model
##
## 891 samples
## 8 predictor
## 2 classes: '0', '1'
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 802, 801, 802, 802, 802, 802, ...
## Resampling results:
##
## Accuracy Kappa
## 0.8271411 0.6290895
로지스틱 회귀 모형의 정확도를 확인해보자.
## Cross-Validated (10 fold) Confusion Matrix
##
## (entries are percentual average cell counts across resamples)
##
## Reference
## Prediction 0 1
## 0 54.2 9.9
## 1 7.4 28.5
##
## Accuracy (average) : 0.8272
로지스틱 회귀 분석 모델에서 각 특성별로 중요성을 확인해보자.
lr_importance <- varImp(lr_model)
ggplot(lr_importance, aes(x = reorder(variable, importance), y = importance)) +
geom_bar(stat = "identity") +
labs(title = " Importance of predictors", x = "Predictors", y = "Importance") +
theme_light()테스트 셋을 사용하여 예측해보자
solution_lr 을 데이터 프레임 형식으로 저장하자.
solution_lr 을 파일로 만들자
로지스틱 회귀 정확도 : 0.8272
이제 마지막 머신러닝 알고리즘인 네이브 베이즈를 사용해 보자.
응답 변수인 "Survived*"가 없는 training 데이터 세트를 생성만들고, 다음으로 생존 변수만 포함된 세트를 만들어보자.
Naive Bayes를 크로스 유효성 검사로 모델링.
train의 변수를 활용하여 모델 생성.
set.seed(222) # Set random seed
nb_model <- train(Survived ~.,
data = train,
method = "nb",
trControl = fitControl); print(nb_model)## Naive Bayes
##
## 891 samples
## 8 predictor
## 2 classes: '0', '1'
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 802, 801, 802, 802, 802, 802, ...
## Resampling results across tuning parameters:
##
## usekernel Accuracy Kappa
## FALSE 0.8024844 0.5783244
## TRUE 0.7923596 0.5276528
##
## Tuning parameter 'fL' was held constant at a value of 0
## Tuning
## parameter 'adjust' was held constant at a value of 1
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were fL = 0, usekernel = FALSE and adjust
## = 1.
모델의 정확도를 확인해자.
## Cross-Validated (10 fold) Confusion Matrix
##
## (entries are percentual average cell counts across resamples)
##
## Reference
## Prediction 0 1
## 0 52.5 10.7
## 1 9.1 27.7
##
## Accuracy (average) : 0.8025
각 변수별로 나이브 베이즈 모델에서의 중요도를 확인해보자.
nb_importance <- varImp(nb_model)
ggplot(nb_importance, aes(x= reorder(variable, importance), y = importance)) +
geom_bar(stat = "identity") +
labs(title = "Importance of predictors", x = "Predictors", y = "Importance") +
theme_light()생존률 예측에 있어, 생성한 나이브 베이즈 모델을 사용하여 test data set을 예측하지 않을 것이다.
test data로 예측을 할 것이다.
solution_nb를 데이터 프레임 형식으로 저장하자.
파일로 저장하자.
나이브 베이즈 정확도 : 0.8025