ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kaggle_titanic] R의 Naive Bayes로 생존자 분류해보기
    My practice 2021. 1. 19. 00:00

     

    Titanic (1997), James Cameron

     


     

    
    library(dplyr)
    library(ggplot2)
    library(e1071)
    library(caret)
    library(Biocomb)
    library(FSelector)
    
    test=read.csv('test.csv')
    train=read.csv('train.csv')
    
    head(train)
    head(test)
    
    #Pclass(티켓등급), Sibsp(형제자매배우자), Parch(부모님)
    #Fare(여객운임), Cabin(객실번호), Embarked(승선항)
    
    #Name, Ticket는 제외 : 과연 의미가 있을까?
    #Cabin 제외 : 결측 너무 많음
    
    train=select(train,-c("Name","Ticket","Cabin"))
    test=select(test,-c("Name","Ticket","Cabin"))
    submission=read.csv("gender_submission.csv")
    
    #########################################################
    
    table(is.na(train$Survived))
    table(is.na(train$Pclass))
    table(is.na(train$Sex))
    table(is.na(train$Age)) # => 결측치 있음
    table(is.na(train$SibSp))
    table(is.na(train$Parch))
    table(is.na(train$Fare))
    table(is.na(train$Embarked))
    
    #########################################################
    
    #Age 결측치 살펴보기
    NAtrain=train[is.na(train$Age),]
    table(NAtrain$Survived)
    table(train$Survived)
    
    p1=52/(125+52)
    n1=125+52
    p2=(342-52)/(342+549-52-125)
    n2=342+549-52-125
    
    (p1-p2)/sqrt((p1*(1-p1)/n1)+(p2*(1-p2)/n2))
    #p<-2.89이므로 나이 미상인 행의 생존률은 나이가 밝혀진 행에 비해 낮다.
    
    #Age를 유청소년0~19, 청년20~39, 중년40~59, 장년60~, 미상NA로 범주화
    train$Age[train$Age<10]=1
    train$Age[train$Age<20&train$Age>=10]=2
    train$Age[train$Age<30&train$Age>=20]=3
    train$Age[train$Age<40&train$Age>=30]=4
    train$Age[train$Age<50&train$Age>=40]=5
    train$Age[train$Age<60&train$Age>=50]=6
    train$Age[train$Age>=60]=7
    train$Age[is.na(train$Age)]=9
    
    test$Age[test$Age<10]=1
    test$Age[test$Age<20&test$Age>=10]=2
    test$Age[test$Age<30&test$Age>=20]=3
    test$Age[test$Age<40&test$Age>=30]=4
    test$Age[test$Age<50&test$Age>=40]=5
    test$Age[test$Age<60&test$Age>=50]=6
    test$Age[test$Age>=60]=7
    test$Age[is.na(test$Age)]=9
    
    train$Age=as.factor(train$Age)
    test$Age=as.factor(test$Age)
    
    train$Survived=as.factor(train$Survived)
    test$Survived=as.factor(test$Survived)
    
    train$Pclass=as.factor(train$Pclass)
    test$Pclass=as.factor(test$Pclass)
    
    train$Sex=as.factor(train$Sex)
    test$Sex=as.factor(test$Sex)
    
    train$SibSp=as.factor(train$SibSp)
    test$SibSp=as.factor(test$SibSp)
    
    train$Parch=as.factor(train$Parch)
    test$Parch=as.factor(test$Parch)
    
    train$Embarked=as.factor(train$Embarked)
    test$Embarked=as.factor(test$Embarked)
    
    #########################################################
    
    par(mfrow=c(2,3))
    
    #Sex : Survived
    Tab=table(train$Survived,train$Sex)
    barplot(Tab,xlab="Sex",main="Sex : Survived",
            col=c("red","green"))
    legend("topleft",c("dead","alive"),col=c("red","green"),pch=17)
    
    #Pclass : Survived
    Tab=table(train$Survived,train$Pclass)
    barplot(Tab,xlab="Pclass",main="Pclass : Survived",
            col=c("red","green"))
    legend("topleft",c("dead","alive"),col=c("red","green"),pch=17)
    
    #SibSp : Survived
    Tab=table(train$Survived,train$SibSp)
    barplot(Tab,xlab="SibSp",main="SibSp : Survived",
            col=c("red","green"))
    legend("topright",c("dead","alive"),col=c("red","green"),pch=17)
    
    #Parch : Survived
    Tab=table(train$Survived,train$Parch)
    barplot(Tab,xlab="Parch",main="Parch : Survived",
            col=c("red","green"))
    legend("topright",c("dead","alive"),col=c("red","green"),pch=17)
    
    
    #Embarked : Survived
    Tab=table(train$Survived,train$Embarked)
    barplot(Tab,xlab="Embarked",main="Embarked : Survived",
            col=c("red","green"))
    legend("topleft",c("dead","alive"),col=c("red","green"),pch=17)
    
    #Age : Survived
    Tab=table(train$Survived,train$Age)
    barplot(Tab,xlab="Age",main="Age : Survived",
            col=c("red","green"))
    legend("topleft",c("dead","alive"),col=c("red","green"),pch=17)
    
    par(mfrow=c(1,1))
    
    #Fare : Survived
    Tab=table(train$Survived,train$Fare)
    hist(train$Fare)
    hist(train$Fare[train$Survived==0],xlim=c(0,500),n=30)
    hist(train$Fare[train$Survived==1],xlim=c(0,500),n=30)
    
    #########################################################
    
    train2=train
    train2$SP=as.numeric(as.character(train$SibSp))+
      as.numeric(as.character(train$Parch))
    
    test2=test
    test2$SP=as.numeric(as.character(test$SibSp))+
      as.numeric(as.character(test$Parch))
    
    #동행인의 수을 나타내는 변수 SP 등록
    train=train2[,-c(6,7)]
    test=test2[,-c(5,6)]
    
    #혼자왔으면?
    Tab=table(train$Survived,train$SP)
    barplot(Tab,xlab="SP",main="SP : Survived",
            col=c("red","green"))
    legend("topright",c("dead","alive"),col=c("red","green"),pch=17)
    #혼자 온 사람이 많이 죽는 경향 있음.
    
    train$SP[train$SP>=4]=9
    test$SP[test$SP>=4]=9
    
    train$SP=as.factor(train$SP)
    test$SP=as.factor(test$SP)
    
    #########################################################
    
    #train split
    nrow(train)
    
    set.seed(111)
    val_ind=sample(891,200)
    
    validset=train[val_ind,]
    trainset=train[-val_ind,]
    
    model_NB=naiveBayes(Survived~.-PassengerId, data=trainset)
    
    #library(randomForest)
    #model_RF=randomForest(Survived~.-PassengerId,data=trainset)
    
    yhat=predict(model_NB,newdata=validset)
    
    confusionMatrix(validset$Survived, yhat)
      

     


     

    0. data는 Kaggle에서 아마도 가장 유명한 Competition인 www.kaggle.com/c/titanic 을 이용했다.

     

    1. Name과 Ticket, Cabin은 제외하였다. Name과 Ticket은 텍스트 형태라서 제외했고, Cabin은 결측치가 너무 많았다. 다면 Name의 mr나 miss, mrs와 같은 것을 이용할 수도 있겠고, Ticket 변수를 좀 더 유심히 살펴보면 Ticket에 대한 정보를 얻어낼 수도 있을 것이라고 생각한다. 다만 Naive Bayes에 관해 그냥 나이브 베이즈를 이용한 분석을 해보려던 의도로 짠 코드기 때문에 대강 넘어갔다.

     

    2. 남은 변수 중에서 Age(나이)가 유일하게 결측치가 있었다. 근데 결측치를 갖는 행의 Survived(y)값에 대한 비율 검정을 해보니까, 검정값이 -2.89 정도로, 결측이 아닌 행과 차이가 있었다. 따라서 우선 미상(9)로 놔두고, 나머지 나이에 대해서는 10살 간격으로 범주화해주었다.

     

    3.  수치형 변수인 Fare를 제외한 나머지 범주형 변수들에 대해서 barplot을 그려주었다.

    성별, 티켓의 등급, 동행한 형제자매 및 부모의 인원 수, 승선지, 나이 변수 모두가 생존 여부와 관련이 있어보이는 plot이다.

     

    4. 동행자의 수를 나타내는 변수 SibSp와 Parch를 한 변수로 통합하였다.

    혼자 온 사람이랑, 1~3명의 가족이랑 같이 온 사람이랑 생존 여부에 차이가 있다. 4명 이상의 경우는 그 수도 적고, 다소 special한 경우로 보인다. 즉 4명 이상의 경우를 하나의 범주로 합치면

    이렇게 되겠다.

    인터넷에 있는 다른 코드들에는 0명인 경우에 생존률이 낮아짐을 반영하기 위해서 이를 설명하는 변수를 추가하기도 하지만, 지금 이 코드에서는 분류기로 결국 NaiveBayes를 이용할 예정이므로 별로 의미가 없는 변수이다. 어차피 factor로 들어갈 것이기 때문에, 동행인이 0명인지 여부를 나타내는 설명변수는 불필요할 것이라고 판단했다.

     

    5. 모델링은 e1071 패키지의 "naiveBayes( )" 를 이용했다. test set을 이용해서 Kaggle의 리더보드에 올려보는 것을 통해 평가할 수도 있겠지만, 일단은 train set에서 validation set을 추출하여 검증해보기로 하였다.

     

    
    confusionMatrix(validset$Survived, yhat)
    Confusion Matrix and Statistics
    
              Reference
    Prediction   0   1
             0 114  12
             1  28  46
                                              
                   Accuracy : 0.8             
                     95% CI : (0.7378, 0.8531)
        No Information Rate : 0.71            
        P-Value [Acc > NIR] : 0.002456        
                                              
                      Kappa : 0.551           
                                              
     Mcnemar's Test P-Value : 0.017706        
                                              
                Sensitivity : 0.8028          
                Specificity : 0.7931          
             Pos Pred Value : 0.9048          
             Neg Pred Value : 0.6216          
                 Prevalence : 0.7100          
             Detection Rate : 0.5700          
       Detection Prevalence : 0.6300          
          Balanced Accuracy : 0.7980          
                                              
           'Positive' Class : 0    
           
    

     

    0.8 정도의 나쁘지 않은 결과가 나왔다. 다만, RandomForest에 같은 조건으로 넣었을 때는 0.84 정도의 정확도가 나온 것으로 봐서, NaiveBayes를 이용하여 더 나은 결과를 얻기 위해서는 조금 더 자세한 전처리가 필요할 것으로 보인다.

     


     

    댓글

since 2021