R study

R을 이용한 의사결정 나무(decision tree). 내 맘대로 인공지능

발킴이 2023. 3. 31. 12:44

 학교에서 데이터 마이닝 수업을 듣다가 의사결정 나무라는 간단한 인공지능기법을 알게 되었다. 내 인생에서. 인공지능, 즉 AI 분야는 살면서 절대로 이해할 수 없는 미지의 세계라고 생각했다.(아직 많이 부족하지만...) 하지만 우연히 연이 닿아 이렇게 의사결정 나무라는 것을 배우게 되었다.

 데이터 마이닝 수업을 들으면서 드는 생각은 사람들은 참 똑똑하다는 것이다. 어떻게 그런 의문을 가졌는지도 신기하고 또 그것을 해결하는 방법까지 고안해 내는 능력이 같은 인간으로서 참 대단하다고 생각했다. 또 아직은 내가 그들에 비해 너무 부족하다고 생각이 든다.

 그래서 오늘은 학교에서 배운 것을 바탕으로 내 맘대로 인공지능을 사용해보려 한다. 내가 하는 방법이 맞는지는 장담할 수 없다. 말 그대로 내 맘대로이기 때문이다. 그렇기 때문에 너그러운 마음으로 나의 소설을 봐줬으면 한다.

 

1. 데이터 소개

<통신사 고객 이탈 데이터>
성별, 자녀의 수, 평균 통화 횟수와 같은 통신사 고객 데이터가 있다. 그리고 이탈을 했는지 안했는지 알려주는 열이 존재한다. 
-데이터 수: 5000개
-행: 5000, 열:20

 이 데이터에서 내가 원하는 타겟 변수는 고객이 이탈을 했는지 안 했는지 알려주는"churn"이라는 변수이다. 타깃 변수란 분석가가 관심을 가지고 알고 싶어 하는 변수이다. churn을 타깃 변수로 잡고 의사결정나무를 이용해서 어떤 고객이 이탈을 하는지 알아보고 의사결정나무를 이용해서 테스트 데이터를 예측해 보겠다.

 우선 의사결정나무가 무엇인지! 내가 이해한 만큼 설명해 보겠다.(정확하지 않을 수 있다!)

의사결정나무
타깃 변수의 순수도를 높이기 위해 여러 변수들을 사용하여 분류화하는 것

 원래 아는 만큼 보이는 것인데 모르는 게 많아서 이 정도밖에 표현을 못하겠다. 이제 R을 사용해서 분석을 진행해 보겠다.

 

2. 데이터 전처리

> head(cm_leave)
  state account_length     area_code international_plan voice_mail_plan
1    HI            101 area_code_510                 no              no
2    MT            137 area_code_510                 no              no
3    OH            103 area_code_408                 no             yes
4    NM             99 area_code_415                 no              no
5    SC            108 area_code_415                 no              no
6    IA            117 area_code_415                 no              no
  number_vmail_messages total_day_minutes total_day_calls total_day_charge
1                     0              70.9             123            12.05
2                     0             223.6              86            38.01
3                    29             294.7              95            50.10
4                     0             216.8             123            36.86
5                     0             197.4              78            33.56
6                     0             226.5              85            38.51
  total_eve_minutes total_eve_calls total_eve_charge total_night_minutes total_night_calls
1             211.9              73            18.01               236.0                73
2             244.8             139            20.81                94.2                81
3             237.3             105            20.17               300.3               127
4             126.4              88            10.74               220.6                82
5             124.0             101            10.54               204.5               107
6             141.6              68            12.04               223.0                90
  total_night_charge total_intl_minutes total_intl_calls total_intl_charge
1              10.62               10.6                3              2.86
2               4.24                9.5                7              2.57
3              13.51               13.7                6              3.70
4               9.93               15.7                2              4.24
5               9.20                7.7                4              2.08
6              10.04                6.9                5              1.86
  number_customer_service_calls churn
1                             3    no
2                             0    no
3                             1    no
4                             1    no
5                             2    no
6                             1    no

 열이 너무 많아서 복잡해 보인다. 하지만 제일 중요한 데이터는 마지막에 있는 churn이라는 변수이다. 6개 행만 봐서 다 no라고 적혀 있지만 많은 데이터 속에 yes도 있을 것이다. 대충 R이 데이터를 잘 읽었다는 것만 파악하고 다음으로 넘어가자.

table(cm_leave$churn) # observe churn column
cm_leave$churn <- factor(cm_leave$churn,labels=c("no","yes")) # return to factor
> table(cm_leave$churn) # observe churn column

  no  yes 
4293  707

 그래도 혹시 모르니 tabl()을 이용해 churn에 no 값 말고 yes 값도 있는지 확인해 봤다. 그리고 이건 맞는지 잘 모르겠지만 의사결정나무가 타깃 변수를 자동으로 범주화시켜서 처리한다고는 하지만 그래도 factor 값으로 변환하는 게 오류가 덜 난다고? 해서 churn열의 모든 값을 factor로 변환해 줬다.

nrow(cm_leave) # count number of rows
stData <- cm_leave[1:4000,] # Allocate 80% of the data to the study dataset
preData <- cm_leave[4001:5000,] # Allocate the remaining 20% of the data

 그리고 가장 중요한 부분! 데이터를 인공지능이 학습할 데이터와 예측 데이터로 나누는 것이다. 원래 검증 데이터도 필요하지만 데이터 수가 모자란 관계로 이 두 가지만 진행하도록 하겠다. 학습용 데이터는 모집단의 80%만 추출하였고 나머지 20%는 예측용 데이터로 남겨뒀다.

 

3. 인공지능 학습 시키기

library(rpart) # library load to use decision tree
dTree_leave <- rpart(churn~.,data=stData) # make decision tree using the study data
dTree_leave 

plot(dTree_leave) 
text(dTree_leave) #visualize

 

 열 개수가 많아서 조금 겹치긴 하지만 의사결정나무가 학습해서 낸 결과이다. 밑으로 다른 변수를 기준으로 타깃 변수를 계속해서 분류하기 때문에 나무가 가지를 치는 것과 비슷하다 하여 의사결정나무라고 이름을 지은 것 같다. 영어로 된 텍스트는 의사결정 나무가 분기할 때 쓴 기준들이다. 

 여기서 끝나면 좋겠지만 과적합 이슈가 있기 때문에 그것도 한번 알아보려 한다.

plotcp(dTree_leave) #check over fitting

 과적합이란 인공지능이 학습을 하다가 학습 데이터에 너무 빠져버려서? 오류가 증가하는 현상이다. 그래서 나무가 분기할 때 너무 많이 분기하면 안 된다. 오류가 증가하는 지점 전까지만 분기하도록 해야 한다. 그래서 과적합이 일어나지 않도록 다시 의사결정나무를 만들었다.

ptree<-prune(dTree_leave, cp= dTree_leave$cptable[which.min(dTree_leave$cptable[,"xerror"]),"CP"]) 
# select the number of branches with the least amount of errors
plot(ptree)
text(ptree)

 그랬더니 이런 결과가 나왔다. 이제 데이터를 학습한 이 의사결정 나무를 가지고  테스트 데이터를 예측해 보겠다. 즉, 사람이 아닌 이 인공지능이 새로운 데이터를 보고 통신사 고객이 이탈할지 안 할지를 예측하는 것이다!!! 

 

4. 예측하기

library(caret) # prepare prediction
predict_leave <- predict(ptree, preData, type="class") # predict the outcome using preData
confusionMatrix(predict_leave, preData$churn) # constructing confusion matrix
> confusionMatrix(predict_leave, preData$churn) # constructing confusion matrix
Confusion Matrix and Statistics

          Reference
Prediction  no yes
       no  826  68
       yes   5 101
                                          
               Accuracy : 0.927           
                 95% CI : (0.9091, 0.9423)
    No Information Rate : 0.831           
    P-Value [Acc > NIR] : < 2.2e-16       
                                          
                  Kappa : 0.6948          
                                          
 Mcnemar's Test P-Value : 3.971e-13       
                                          
            Sensitivity : 0.9940          
            Specificity : 0.5976          
         Pos Pred Value : 0.9239          
         Neg Pred Value : 0.9528          
             Prevalence : 0.8310          
         Detection Rate : 0.8260          
   Detection Prevalence : 0.8940          
      Balanced Accuracy : 0.7958          
                                          
       'Positive' Class : no

 오류 없이 예측을 했고 무사히 결과 값을 반환했다. 그리고 정확성을 판단하기 위해서 혼돈행렬을 만들어봤다. 부족하지만 혼돈행렬을 해석해 보겠다. 92.7%의 정확도로 의사결정나무가 예측했다. 하지만 그렇다고 해서 정확한 건 아니다. 왜냐하면 민간도는 99% 이지만 특이도가 60% 정도 되기 때문이다. 이 말은 이탈하지 않은 사람은 잘 맞췄지만 이탈한 사람은 잘 맞추지 못했음을 의미한다. 나는 이탈한 사람을 알고 싶은데 그 정확도는 이탈하지 않은 사람을 예측하는 것에 비해 떨어진다. 직관적으로 봐도 실제 이탈한 사람은 169 명(테스트 데이터에서)인데 의사결정나무가 예측해서 맞춘 것은 101명 정도이다. 즉 나머지 68명은 제대로 예측하지 못한 것이다.

 

5. 시사점

 오늘은  내 맘대로 의사결정나무를 사용해서 나름 인공지능과 친해져 봤다. 의사결정 나무를 배우면서 가장 먼저 든 생각은 '회사에서 퇴사하는 사람에 대한 잘 정제된 데이터가 있다면 진짜 퇴사를 예측하는 게 가능할 수도 있겠다.'는 것이다. 퇴사를 T or F형태의 타깃변수로 설정하고 조직원들의 여러 가지 정보들을 가지고 분류화 작업을 한다면, 어떤 사람이 퇴사를 하는지, 어떤 행동이 퇴사로 이어지는지 까지 알 수 있을 것이다.

 하지만 "과연 이게 윤리적으로 옳은 일인가?"라는 생각이 든다. 결국 지금 내가 하는 것은 1984의 빅브라더가 하는 짓이 아닐까? 자신의 정보가 회사로 계속 빠져나가고 회사는 그 정보를 가지고 자신을 관찰하는데 어떤 사람이 좋아할까? 그래도 그 목적이 감시가 아니라 회사원의 성장이라면 그나마 괜찮을 것 같기도 하다. 결국, HR analytics가 정당화되기 위해서는 그 목적을 조직의 성장으로 설정할 필요가 있다. 그리고 그 목적에 따라 적절하게 윤리적으로 사용해야 할 것이다.

 최근에 살면서 별로 신기할 것이 없었는데 이건 배우면서 계속 신기하다는 생각만 들었다. 기술이 신기하다기보다는 이런 논리가 참신하게 다가왔다. 완전 새로운 분야를 배운다는 것은 두렵고 힘들지만 새로운 세상을 볼 수 있다는 점에서 참으로 가치 있는 일이다!