ls()
## character(0)
rm(list = ls())
getwd()
## [1] "D:/data"
library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.5     v purrr   0.3.4
## v tibble  3.1.6     v dplyr   1.0.9
## v tidyr   1.2.0     v stringr 1.4.0
## v readr   2.1.0     v forcats 0.5.1
## Warning: 패키지 'tidyr'는 R 버전 4.1.3에서 작성되었습니다
## Warning: 패키지 'dplyr'는 R 버전 4.1.3에서 작성되었습니다
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(caret)
## 필요한 패키지를 로딩중입니다: lattice
## 
## 다음의 패키지를 부착합니다: 'caret'
## The following object is masked from 'package:purrr':
## 
##     lift
library(recipes)
## Warning: 패키지 'recipes'는 R 버전 4.1.3에서 작성되었습니다
## 
## 다음의 패키지를 부착합니다: 'recipes'
## The following object is masked from 'package:stringr':
## 
##     fixed
## The following object is masked from 'package:stats':
## 
##     step
df<-read.csv("travel_data.csv")
df %>% glimpse
## Rows: 1,987
## Columns: 10
## $ INDEX               <int> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ~
## $ Age                 <int> 31, 31, 34, 28, 28, 25, 31, 31, 28, 33, 31, 26, 32~
## $ Employment.Type     <chr> "Government Sector", "Private Sector/Self Employed~
## $ GraduateOrNot       <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "No", "Yes", "Y~
## $ AnnualIncome        <int> 400000, 1250000, 500000, 700000, 700000, 1150000, ~
## $ FamilyMembers       <int> 6, 7, 4, 3, 8, 4, 4, 3, 6, 3, 9, 5, 6, 6, 3, 7, 4,~
## $ ChronicDiseases     <int> 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1,~
## $ FrequentFlyer       <chr> "No", "No", "No", "No", "Yes", "No", "No", "Yes", ~
## $ EverTravelledAbroad <chr> "No", "No", "No", "No", "No", "No", "No", "Yes", "~
## $ TravelInsurance     <int> 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0,~
#train/test 0.75:0.25
set.seed(1357)
train_list<-createDataPartition(y=df$TravelInsurance,p=0.75,list=FALSE)
head(train_list)
##      Resample1
## [1,]         3
## [2,]         4
## [3,]         5
## [4,]         8
## [5,]         9
## [6,]        10
#임의로 추출된 번호에 데이터를 붙여주는 작업
df_train<-df[train_list,]
df_test<-df[-train_list,]
#데이터가 몇개인가 확인
NROW(df_train)
## [1] 1491
NROW(df_test)
## [1] 496
df_train %>% glimpse
## Rows: 1,491
## Columns: 10
## $ INDEX               <int> 2, 3, 4, 7, 8, 9, 10, 11, 13, 16, 17, 18, 19, 20, ~
## $ Age                 <int> 34, 28, 28, 31, 28, 33, 31, 26, 31, 28, 28, 29, 34~
## $ Employment.Type     <chr> "Private Sector/Self Employed", "Private Sector/Se~
## $ GraduateOrNot       <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "~
## $ AnnualIncome        <int> 500000, 700000, 700000, 1350000, 1450000, 800000, ~
## $ FamilyMembers       <int> 4, 3, 8, 3, 6, 3, 9, 5, 6, 4, 7, 5, 2, 6, 3, 4, 9,~
## $ ChronicDiseases     <int> 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,~
## $ FrequentFlyer       <chr> "No", "No", "Yes", "Yes", "Yes", "Yes", "No", "Yes~
## $ EverTravelledAbroad <chr> "No", "No", "No", "Yes", "Yes", "No", "No", "Yes",~
## $ TravelInsurance     <int> 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1,~
df_test %>% glimpse
## Rows: 496
## Columns: 10
## $ INDEX               <int> 0, 1, 5, 6, 12, 14, 15, 27, 33, 37, 38, 39, 43, 46~
## $ Age                 <int> 31, 31, 25, 31, 32, 31, 34, 28, 32, 34, 34, 33, 28~
## $ Employment.Type     <chr> "Government Sector", "Private Sector/Self Employed~
## $ GraduateOrNot       <chr> "Yes", "Yes", "No", "Yes", "Yes", "Yes", "Yes", "Y~
## $ AnnualIncome        <int> 400000, 1250000, 1150000, 1300000, 850000, 400000,~
## $ FamilyMembers       <int> 6, 7, 4, 4, 6, 3, 7, 2, 3, 4, 2, 5, 4, 4, 3, 3, 9,~
## $ ChronicDiseases     <int> 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,~
## $ FrequentFlyer       <chr> "No", "No", "No", "No", "No", "No", "No", "Yes", "~
## $ EverTravelledAbroad <chr> "No", "No", "No", "No", "No", "No", "No", "No", "N~
## $ TravelInsurance     <int> 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1,~
#train data와 test data 구분
df_train %>% mutate(index="train")->df_train
df_test %>% mutate(index="test")->df_test
bind_rows(df_train,df_test)->full
full %>% glimpse
## Rows: 1,987
## Columns: 11
## $ INDEX               <int> 2, 3, 4, 7, 8, 9, 10, 11, 13, 16, 17, 18, 19, 20, ~
## $ Age                 <int> 34, 28, 28, 31, 28, 33, 31, 26, 31, 28, 28, 29, 34~
## $ Employment.Type     <chr> "Private Sector/Self Employed", "Private Sector/Se~
## $ GraduateOrNot       <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "Yes", "~
## $ AnnualIncome        <int> 500000, 700000, 700000, 1350000, 1450000, 800000, ~
## $ FamilyMembers       <int> 4, 3, 8, 3, 6, 3, 9, 5, 6, 4, 7, 5, 2, 6, 3, 4, 9,~
## $ ChronicDiseases     <int> 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,~
## $ FrequentFlyer       <chr> "No", "No", "Yes", "Yes", "Yes", "Yes", "No", "Yes~
## $ EverTravelledAbroad <chr> "No", "No", "No", "Yes", "Yes", "No", "No", "Yes",~
## $ TravelInsurance     <int> 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1,~
## $ index               <chr> "train", "train", "train", "train", "train", "trai~
#2 목표변수, 기타변수 변환,  *29행과 30번행의 명령어가 바뀌면 안됨
full$TravelInsurance<-ifelse(full$TravelInsurance==0,"미가입","가입")
full$TravelInsurance<-as.factor(full$TravelInsurance)
full$GraduateOrNot<-as.factor(full$GraduateOrNot)
full$FrequentFlyer<-as.factor(full$FrequentFlyer)
full$EverTravelledAbroad<-as.factor(full$EverTravelledAbroad)
full %>% glimpse
## Rows: 1,987
## Columns: 11
## $ INDEX               <int> 2, 3, 4, 7, 8, 9, 10, 11, 13, 16, 17, 18, 19, 20, ~
## $ Age                 <int> 34, 28, 28, 31, 28, 33, 31, 26, 31, 28, 28, 29, 34~
## $ Employment.Type     <chr> "Private Sector/Self Employed", "Private Sector/Se~
## $ GraduateOrNot       <fct> Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, ~
## $ AnnualIncome        <int> 500000, 700000, 700000, 1350000, 1450000, 800000, ~
## $ FamilyMembers       <int> 4, 3, 8, 3, 6, 3, 9, 5, 6, 4, 7, 5, 2, 6, 3, 4, 9,~
## $ ChronicDiseases     <int> 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,~
## $ FrequentFlyer       <fct> No, No, Yes, Yes, Yes, Yes, No, Yes, Yes, No, No, ~
## $ EverTravelledAbroad <fct> No, No, No, Yes, Yes, No, No, Yes, Yes, No, No, No~
## $ TravelInsurance     <fct> 가입, 미가입, 미가입, 가입, 가입, 미가입, 미가입, ~
## $ index               <chr> "train", "train", "train", "train", "train", "trai~
#3 결측값 확인
colSums(is.na(full))
##               INDEX                 Age     Employment.Type       GraduateOrNot 
##                   0                   0                   0                   0 
##        AnnualIncome       FamilyMembers     ChronicDiseases       FrequentFlyer 
##                   0                   0                   0                   0 
## EverTravelledAbroad     TravelInsurance               index 
##                   0                   0                   0
summary(is.na(full))
##    INDEX            Age          Employment.Type GraduateOrNot  
##  Mode :logical   Mode :logical   Mode :logical   Mode :logical  
##  FALSE:1987      FALSE:1987      FALSE:1987      FALSE:1987     
##  AnnualIncome    FamilyMembers   ChronicDiseases FrequentFlyer  
##  Mode :logical   Mode :logical   Mode :logical   Mode :logical  
##  FALSE:1987      FALSE:1987      FALSE:1987      FALSE:1987     
##  EverTravelledAbroad TravelInsurance   index        
##  Mode :logical       Mode :logical   Mode :logical  
##  FALSE:1987          FALSE:1987      FALSE:1987
names(full)
##  [1] "INDEX"               "Age"                 "Employment.Type"    
##  [4] "GraduateOrNot"       "AnnualIncome"        "FamilyMembers"      
##  [7] "ChronicDiseases"     "FrequentFlyer"       "EverTravelledAbroad"
## [10] "TravelInsurance"     "index"
#4 데이터 전처리
recipe(TravelInsurance~.,data=full) %>% 
  step_YeoJohnson(Age,AnnualIncome,FamilyMembers) %>% 
  step_center(Age,AnnualIncome,FamilyMembers) %>% 
  step_scale(Age,AnnualIncome,FamilyMembers) %>% 
  prep() %>% juice()->data
data %>% glimpse
## Rows: 1,987
## Columns: 11
## $ INDEX               <int> 2, 3, 4, 7, 8, 9, 10, 11, 13, 16, 17, 18, 19, 20, ~
## $ Age                 <dbl> 1.4182229, -0.5150177, -0.5150177, 0.5290744, -0.5~
## $ Employment.Type     <fct> Private Sector/Self Employed, Private Sector/Self ~
## $ GraduateOrNot       <fct> Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, ~
## $ AnnualIncome        <dbl> -1.16128743, -0.56552847, -0.56552847, 1.08672642,~
## $ FamilyMembers       <dbl> -0.3760749, -1.1525825, 1.7698222, -1.1525825, 0.8~
## $ ChronicDiseases     <int> 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,~
## $ FrequentFlyer       <fct> No, No, Yes, Yes, Yes, Yes, No, Yes, Yes, No, No, ~
## $ EverTravelledAbroad <fct> No, No, No, Yes, Yes, No, No, Yes, Yes, No, No, No~
## $ index               <fct> train, train, train, train, train, train, train, t~
## $ TravelInsurance     <fct> 가입, 미가입, 미가입, 가입, 가입, 미가입, 미가입, ~
View(data)
data %>% filter(index=="train") %>% select(-index)->train
data %>% filter(index=="test") %>% select(-index)->test

#caret package 역할
#cv(교차검증) 데이터를 10등분해서 반복 계산
ctrl<-trainControl(method="cv",summaryFunction = twoClassSummary,
                   classProbs = TRUE)
#roc : 분류모형 평가
train(TravelInsurance~.,data=train,
      method='rpart',metric="ROC",
      trControl=ctrl)->rpfit
rpfit
## CART 
## 
## 1491 samples
##    9 predictor
##    2 classes: '가입', '미가입' 
## 
## No pre-processing
## Resampling: Cross-Validated (10 fold) 
## Summary of sample sizes: 1342, 1342, 1342, 1342, 1341, 1342, ... 
## Resampling results across tuning parameters:
## 
##   cp           ROC        Sens       Spec     
##   0.002358491  0.7800814  0.5754717  0.9593965
##   0.056603774  0.7331815  0.4830189  0.9718857
##   0.401886792  0.5834763  0.1773585  0.9895941
## 
## ROC was used to select the optimal model using the largest value.
## The final value used for the model was cp = 0.002358491.
#Confusion matrics(google)
#rpart cp complexy parameter 이 포인트에서 분할가지수를 선택한다.
confusionMatrix(rpfit)
## Cross-Validated (10 fold) Confusion Matrix 
## 
## (entries are percentual average cell counts across resamples)
##  
##           Reference
## Prediction 가입 미가입
##     가입   20.5    2.6
##     미가입 15.1   61.8
##                             
##  Accuracy (average) : 0.8229
test %>% glimpse
## Rows: 496
## Columns: 10
## $ INDEX               <int> 0, 1, 5, 6, 12, 14, 15, 27, 33, 37, 38, 39, 43, 46~
## $ Age                 <dbl> 0.5290744, 0.5290744, -1.7617299, 0.5290744, 0.840~
## $ Employment.Type     <fct> Government Sector, Private Sector/Self Employed, P~
## $ GraduateOrNot       <fct> Yes, Yes, No, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Y~
## $ AnnualIncome        <dbl> -1.4862039, 0.8519524, 0.6113603, 0.9700295, -0.15~
## $ FamilyMembers       <dbl> 0.8341005, 1.3278276, -0.3760749, -0.3760749, 0.83~
## $ ChronicDiseases     <int> 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,~
## $ FrequentFlyer       <fct> No, No, No, No, No, No, No, Yes, No, No, No, Yes, ~
## $ EverTravelledAbroad <fct> No, No, No, No, No, No, No, No, No, No, No, Yes, N~
## $ TravelInsurance     <fct> 미가입, 미가입, 미가입, 미가입, 가입, 미가입, 미가~
predict(rpfit,test,type='prob')->rffit1
predict(rpfit,test,type='raw')->rffit2
head(rffit1)
##       가입   미가입
## 1 0.190326 0.809674
## 2 0.190326 0.809674
## 3 0.190326 0.809674
## 4 0.190326 0.809674
## 5 0.190326 0.809674
## 6 0.190326 0.809674
head(rffit2)
## [1] 미가입 미가입 미가입 미가입 미가입 미가입
## Levels: 가입 미가입
confusionMatrix(rffit2,test$TravelInsurance)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction 가입 미가입
##     가입    116     14
##     미가입   64    302
##                                           
##                Accuracy : 0.8427          
##                  95% CI : (0.8077, 0.8737)
##     No Information Rate : 0.6371          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.6383          
##                                           
##  Mcnemar's Test P-Value : 2.887e-08       
##                                           
##             Sensitivity : 0.6444          
##             Specificity : 0.9557          
##          Pos Pred Value : 0.8923          
##          Neg Pred Value : 0.8251          
##              Prevalence : 0.3629          
##          Detection Rate : 0.2339          
##    Detection Prevalence : 0.2621          
##       Balanced Accuracy : 0.8001          
##                                           
##        'Positive' Class : 가입            
## 
importance<-varImp(rpfit,scale=FALSE)
print(importance)
## rpart variable importance
## 
##                                                Overall
## AnnualIncome                                  200.4404
## EverTravelledAbroadYes                        122.4265
## FamilyMembers                                  59.1438
## Age                                            39.4285
## FrequentFlyerYes                               35.6629
## Employment.TypePrivate Sector/Self Employed    11.7596
## INDEX                                           3.2728
## ChronicDiseases                                 0.9696
## GraduateOrNotYes                                0.0000
## `Employment.TypePrivate Sector/Self Employed`   0.0000
library(pROC)
## Type 'citation("pROC")' for a citation.
## 
## 다음의 패키지를 부착합니다: 'pROC'
## The following objects are masked from 'package:stats':
## 
##     cov, smooth, var
rffit2_num<-as.numeric(rffit2)
rffit2_num
##   [1] 2 2 2 2 2 2 1 2 2 2 2 1 2 1 2 2 1 2 2 2 2 1 2 2 2 2 1 2 2 2 2 2 2 2 1 1 2
##  [38] 2 2 1 2 1 1 2 1 2 1 2 2 2 1 1 2 2 2 1 2 2 2 2 2 2 2 2 2 1 2 2 2 2 1 2 1 2
##  [75] 2 1 2 2 2 2 2 2 2 1 2 2 2 2 2 1 1 2 2 1 2 1 2 2 2 1 2 2 2 2 1 1 1 2 2 2 2
## [112] 2 2 2 1 2 1 2 1 2 2 1 2 2 1 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 1 2 2 1 1 2 2 2
## [149] 2 2 2 2 2 2 2 2 1 1 2 2 2 2 2 2 2 1 2 1 2 2 2 1 2 2 2 2 2 2 2 2 1 2 2 1 1
## [186] 2 2 2 2 2 2 2 2 2 1 1 2 2 1 2 2 2 2 1 1 1 2 2 2 1 2 1 1 2 2 2 2 2 2 2 2 1
## [223] 1 2 2 1 2 2 1 2 2 2 1 2 2 2 2 2 1 2 2 1 1 2 2 1 2 2 2 2 1 2 2 2 1 1 2 2 2
## [260] 1 1 2 2 1 2 2 2 2 2 1 2 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 2 2 2 1 1 2 2 2 2 2
## [297] 2 2 2 1 2 1 2 2 2 1 1 2 2 2 2 2 2 2 2 2 2 1 2 2 1 2 2 2 1 1 2 1 2 2 2 2 2
## [334] 2 2 2 1 2 2 2 2 1 2 2 2 2 1 2 1 1 1 2 2 2 1 1 2 2 1 2 2 2 2 2 2 2 1 2 1 2
## [371] 2 2 1 2 2 2 2 2 2 1 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 1 2 2 1 2 1 2
## [408] 2 2 2 2 2 2 2 2 1 1 2 1 2 2 1 1 1 1 2 1 2 2 1 2 2 2 1 2 2 1 2 1 2 2 1 2 2
## [445] 2 2 2 2 2 1 1 2 2 2 2 1 2 2 2 2 2 2 2 2 2 1 2 1 2 2 2 1 2 2 2 2 1 2 2 2 2
## [482] 2 1 1 2 1 2 1 2 2 2 1 2 2 1 2
result<-roc(test$TravelInsurance,rffit2_num)
## Setting levels: control = 가입, case = 미가입
## Setting direction: controls < cases
result
## 
## Call:
## roc.default(response = test$TravelInsurance, predictor = rffit2_num)
## 
## Data: rffit2_num in 180 controls (test$TravelInsurance 가입) < 316 cases (test$TravelInsurance 미가입).
## Area under the curve: 0.8001
result$auc
## Area under the curve: 0.8001