YOGYUI

빅데이터분석기사 실기 제2유형 문제 풀이 예시 (3) 본문

Study/자격증

빅데이터분석기사 실기 제2유형 문제 풀이 예시 (3)

요겨 2021. 6. 12. 15:33
반응형

7. 의사 결정 나무

제공되는 패키지 중에 rpart가 있으니 의사결정나무도 준비해가자

(분류 결과를 제일 직관적으로 확인 가능한 모델)

 

library(rpart)
library(rpart.plot)

model_tree <- rpart(y_train$genfac ~ .-cust_id, X_train_proc)
prp(model_tree)

root는 주구매상품인데, 재밌는 건 젓갈과 주방용품(???)을 사는 경우도 남자로 분류가 된다

내점일수가 특정일보다 작으면 남자로 분기되는건 합리적인 것 같다 ㅋㅋ

(약간 어처구니없게도) 환불금액이 분기 노드로 사용되었다... 여자가 환불 금액이 남자보다 큰 사례들이 좀 있나보다...

 

의사 결정 나무는 일반적으로 다른 모델에 비해 분류 성능이 낮고, 훈련 데이터에 과적합될 가능성이 높아서 시험에서 사용하기는 권장하지는 않는다

(시각적 확인 용도로는... 사용할 수는 있다)

 

8. SVM

서포트 벡터 머신(Support Vector Machine)을 위한 패키지인 e1071도 제공된다

library(e1071)

model_svm <- svm(y_train$genfac ~ .-cust_id, X_train_proc)
summary(model_svm)
>
Call:
svm(formula = y_train$genfac ~ . - cust_id, data = X_train_proc)


Parameters:
   SVM-Type:  C-classification 
 SVM-Kernel:  radial 
       cost:  1 

Number of Support Vectors:  3676

 ( 1844 1832 )


Number of Classes:  2 

Levels: 
 남자 여자

SVM은 하이퍼파라미터 튜닝(커널 파라미터)이 핵심인 머신러닝 기법인데, 고도로 숙련된 전문가가 아닌 이상 시험장에 앉아서 2~3시간 안에 완수하기는 힘들지 않나싶다 (개인적으로 그냥 SVM 경험이 일천해서 그렇게 느껴지는 걸수도... ㅎㅎ SVM 쓸바에서 그냥 keras로 DNN 구축해버리니깐...)

 

9. 홀드아웃

분석모델을 만들다보니 모델의 분석 정확도를 측정해봐야 하지 않을까라는 생각이 들었다

(훈련용 데이터 전체를 학습하고 훈련용 데이터 전체를 대상으로 ROC-AUC를 측정하는건 의미가 없다)

(K-교차검증도 생각해볼만 한데, 시험 시간 내에 한큐에 끝내려면 충분히 숙지할 필요가 있어서 패스~)

 

주어지는 데이터는 이미 train, test로 홀드아웃되어있으나, 테스트 데이터는 정답 라벨이 없으므로 모델 성능을 평가할 수 없다. 따라서 train 데이터를 일정 비율로 train data, validation data (검증용 데이터)로 분리한 뒤 train data로 학습, validation data로 분류 성능 계산을 수행하도록 하자

(이제껏 공부했던 거 한번 복습도 할 겸)

 

무작위로 데이터를 분할하면 분할된 데이터 내에서 또 클래스 불균형이 발생할 수 있으므로 caret패키지의 createDataPartition 함수를 사용해 정답 클래스의 비율이 분리된 데이터들에서도 유지되도록 한다

set.seed(210612)

X_train <- read.csv('./data/X_train.csv')
y_train <- read.csv('./data/y_train.csv')
X_test <- read.csv('./data/X_test.csv')

library(dplyr)
X_train <- X_train %>% filter(!cust_id %in% c(1521, 2035))
X_train$주구매상품 <- as.factor(X_train$주구매상품)
X_train$주구매지점 <- as.factor(X_train$주구매지점)
X_train[is.na(X_train$환불금액),]$환불금액 <- 0

X_test$주구매상품 <- as.factor(X_test$주구매상품)
X_test$주구매지점 <- as.factor(X_test$주구매지점)
X_test[is.na(X_test$환불금액),]$환불금액 <- 0

y_train <- y_train %>% filter(!cust_id %in% c(1521, 2035))
y_train$genfac <- ifelse(y_train$gender == 1, "남자", "여자")
y_train$genfac <- as.factor(y_train$genfac)

# Hold-Out: split train data to (train, validation)
library(caret)
split <- createDataPartition(y_train$gender, p=0.8)
X_validation <- X_train[-split$Resample1,]
y_validation <- y_train[-split$Resample1,]
X_train <- X_train[split$Resample1,]
y_train <- y_train[split$Resample1,]

8:2 비율로 나누기 위해 createDataPartition의 인자로 p=0.8을 입력했다

split$Resample1에는 X_train 데이터 길이의 80%에 해당하는 인덱스가 담겨있으니 간단하게 인덱싱으로 데이터를 나눌 수 있다

nrow(X_train)
> [1] 2799

nrow(y_train)
> [1] 2799

nrow(X_validation)
> [1] 699

nrow(y_validation)
> [1] 699

table(y_train$genfac)
>
남자 여자 
1059 1740 

table(y_validation$genfac)
>
남자 여자 
 256  443 

3498 길이의 훈련용 데이터가 2799길이의 새로운 훈련용 데이터, 699길이의 검증용 데이터로 분리되었으며 (4:1 비율), 훈련용 데이터와 검증용 데이터는 남자:여자 라벨의 비율이 각각 1:1.643, 1:1.730으로 비슷하게 분리되었다 

(sample함수로 인덱스를 무작위 추출하면 클래스 비율 유지가 보장되지 않는다!)

 

수치 데이터 정규화 및 훈련용 데이터 업샘플링도 앞서 했던 것과 동일하게 수행

# Data Pre-processing
model_proc <- preProcess(X_train[,c(-1)], method=('range'))
X_train_proc <- predict(model_proc, X_train)
X_validation_proc <- predict(model_proc, X_validation)
X_test_proc <- predict(model_proc, X_test)

# up-sampling
temp <- X_train_proc
temp$genfac <- y_train$genfac
temp2 <- upSample(subset(temp, select=-genfac), temp$genfac)

X_train_proc <- subset(temp2, select=-Class)
y_train <- subset(temp2, select=c(cust_id, Class))
names(y_train) <- c('cust_id', 'genfac')
y_train$gender <- ifelse(y_train$genfac == '남자', 1, 0)
summary(X_train_proc)
>    cust_id          총구매액         최대구매액          환불금액           주구매상품      주구매지점      내점일수       내점당구매건수     주말방문비율       구매주기      
 Min.   :   1.0   Min.   :0.00000   Min.   :0.000000   Min.   :0.000000   기타    : 593   본  점  :1052   Min.   :0.00000   Min.   :0.00000   Min.   :0.0000   Min.   :0.00000  
 1st Qu.: 871.8   1st Qu.:0.02380   1st Qu.:0.006419   1st Qu.:0.000000   가공식품: 580   잠실점  : 473   1st Qu.:0.00361   1st Qu.:0.03162   1st Qu.:0.0000   1st Qu.:0.02410  
 Median :1721.5   Median :0.03248   Median :0.024061   Median :0.000000   농산물  : 326   분당점  : 459   Median :0.02166   Median :0.06324   Median :0.2589   Median :0.08434  
 Mean   :1740.8   Mean   :0.05722   Mean   :0.047887   Mean   :0.014181   화장품  : 242   영등포점: 247   Mean   :0.06093   Mean   :0.08695   Mean   :0.3132   Mean   :0.12981  
 3rd Qu.:2626.2   3rd Qu.:0.06261   3rd Qu.:0.056479   3rd Qu.:0.003639   시티웨어: 210   부산본점: 233   3rd Qu.:0.07581   3rd Qu.:0.11067   3rd Qu.:0.4675   3rd Qu.:0.17470  
 Max.   :3496.0   Max.   :1.00000   Max.   :1.000000   Max.   :1.000000   디자이너: 169   일산점  : 199   Max.   :1.00000   Max.   :1.00000   Max.   :1.0000   Max.   :1.00000  
                                                                          (Other) :1360   (Other) : 817                                                                         
summary(X_validation_proc)
>    cust_id        총구매액         최대구매액           환불금액           주구매상품     주구매지점     내점일수       내점당구매건수     주말방문비율        구매주기      
 Min.   :   0   Min.   :0.02081   Min.   :-0.007844   Min.   :0.000000   기타    :119   본  점  :226   Min.   :0.00000   Min.   :0.00000   Min.   :0.00000   Min.   :0.00000  
 1st Qu.: 896   1st Qu.:0.02371   1st Qu.: 0.006050   1st Qu.:0.000000   가공식품: 92   잠실점  : 95   1st Qu.:0.00361   1st Qu.:0.02846   1st Qu.:0.02277   1st Qu.:0.02410  
 Median :1816   Median :0.03309   Median : 0.023070   Median :0.000000   농산물  : 69   분당점  : 78   Median :0.02527   Median :0.06033   Median :0.25532   Median :0.07229  
 Mean   :1788   Mean   :0.06173   Mean   : 0.053057   Mean   :0.015369   화장품  : 51   부산본점: 56   Mean   :0.06585   Mean   :0.08515   Mean   :0.31073   Mean   :0.12002  
 3rd Qu.:2718   3rd Qu.:0.06496   3rd Qu.: 0.060866   3rd Qu.:0.004155   수산품  : 37   영등포점: 49   3rd Qu.:0.09025   3rd Qu.:0.11563   3rd Qu.:0.46018   3rd Qu.:0.16867  
 Max.   :3499   Max.   :0.74408   Max.   : 1.849360   Max.   :1.064484   디자이너: 36   일산점  : 36   Max.   :1.02527   Max.   :0.73568   Max.   :1.00000   Max.   :0.97590  
                                                                         (Other) :295   (Other) :159                                                                          
summary(X_test_proc)
>    cust_id        총구매액          최대구매액           환불금액           주구매상품     주구매지점     내점일수       내점당구매건수     주말방문비율        구매주기      
 Min.   :3500   Min.   :0.006306   Min.   :-0.098000   Min.   :0.000000   기타    :465   본  점  :726   Min.   :0.00000   Min.   :0.00000   Min.   :0.00000   Min.   :0.00000  
 1st Qu.:4120   1st Qu.:0.024204   1st Qu.: 0.007536   1st Qu.:0.000000   가공식품:395   잠실점  :352   1st Qu.:0.00361   1st Qu.:0.03557   1st Qu.:0.02346   1st Qu.:0.02410  
 Median :4740   Median :0.034913   Median : 0.028128   Median :0.000000   농산물  :235   분당점  :328   Median :0.02888   Median :0.06787   Median :0.25000   Median :0.07831  
 Mean   :4740   Mean   :0.064594   Mean   : 0.056964   Mean   :0.016928   화장품  :177   부산본점:168   Mean   :0.06685   Mean   :0.08630   Mean   :0.29381   Mean   :0.12221  
 3rd Qu.:5361   3rd Qu.:0.075285   3rd Qu.: 0.068759   3rd Qu.:0.005616   시티웨어:168   일산점  :158   3rd Qu.:0.09296   3rd Qu.:0.11265   3rd Qu.:0.42357   3rd Qu.:0.16265  
 Max.   :5981   Max.   :1.226493   Max.   : 1.552562   Max.   :1.645602   디자이너:123   영등포점:150   Max.   :0.79783   Max.   :0.70553   Max.   :1.00000   Max.   :1.06627  
                                                                          (Other) :919   (Other) :600                                                                          
table(y_train$genfac)
>
남자 여자 
1740 1740 

이제 몇몇 머신러닝 알고리즘들에 대해 다음 프로세스를 수행해보자

  1. 훈련용 데이터 X_train_proc, y_train으로 학습
  2. 검증용 데이터 X_validation_proc, y_validation으로 분류 성능 검토
  3. 모델간 분류 성능 비교
model_glm <- glm(y_train$gender ~ .-cust_id, data=X_train_proc, family='binomial')
y_pred_glm <- predict(model_glm, newdata=X_validation_proc, type='response')
Error in model.frame.default(Terms, newdata, na.action = na.action, xlev = object$xlevels) : 
  요인(factor) 주구매상품는 남성 트랜디개의 새로운 수준(levels)들을 가지고 있습니다.

야심차게 시작했는데...

검증용 데이터에 대한 분류 예측 시 오류가 발생한다

메시지를 보니 학습용 데이터에는 '주구매상품::남성 트랜디'가 아예 할당이 되지 않아 학습이 된 적 없던게 문제다

X_train_proc %>% filter(주구매상품=='남성 트랜디')
> [1] cust_id        총구매액       최대구매액     환불금액       주구매상품     주구매지점     내점일수       내점당구매건수 주말방문비율   구매주기      
<0 행> <또는 row.names의 길이가 0입니다>

X_validation_proc %>% filter(주구매상품=='남성 트랜디')
>  cust_id   총구매액 최대구매액   환불금액  주구매상품 주구매지점  내점일수 내점당구매건수 주말방문비율   구매주기
1     227 0.02905105 0.04341165 0.00000000 남성 트랜디     분당점 0.0000000     0.00000000    1.0000000 0.00000000
2    3123 0.23011788 0.11560073 0.04743899 남성 트랜디     본  점 0.2418773     0.05859103    0.5065789 0.03012048

 

훈련용 데이터와 검증용 데이터의 주구매상품 분포를 확인해보자

table(X_train_proc$주구매상품)
>
   가공식품        가구    건강식품        골프        구두        기타 남성 캐주얼 남성 트랜디    남성정장      농산물    대형가전    디자이너 란제리/내의        명품   모피/피혁 
        580          10          39          83          53         593          70           0          18         326           9         169           9          88          63 
       보석    생활잡화    섬유잡화        셔츠      수산품      스포츠    시티웨어        식기        아동        악기    액세서리        육류    일용잡화   젓갈/반찬        주류 
          1          16         115          39         142          78         210           6          39           3           3          54          57          31          16 
   주방가전    주방용품     차/커피    축산가공   침구/수예      캐주얼      커리어 통신/컴퓨터  트래디셔널    피혁잡화      화장품 
         30          31          41          35           3         100           7           3          27          41         242 

table(X_validation_proc$주구매상품)
>
   가공식품        가구    건강식품        골프        구두        기타 남성 캐주얼 남성 트랜디    남성정장      농산물    대형가전    디자이너 란제리/내의        명품   모피/피혁 
         92           2          16          19          12         119          11           2           7          69           1          36           0          25           9 
       보석    생활잡화    섬유잡화        셔츠      수산품      스포츠    시티웨어        식기        아동        악기    액세서리        육류    일용잡화   젓갈/반찬        주류 
          2           3          20           6          37          11          31           3           7           0           2          17          15           6           0 
   주방가전    주방용품     차/커피    축산가공   침구/수예      캐주얼      커리어 통신/컴퓨터  트래디셔널    피혁잡화      화장품 
          7           8           9           8           1          20           2           1           4           8          51 

'주류, '란제리/내의', '악기'가 훈련용 데이터에 몰빵되어 있고, '남성 트랜디'가 검증용에 몰빵되어있다

(훈련 데이터에만 있고 검증 데이터에 없는건 예측시 큰 문제가 되지는 않는다)

 

주구매상품 뿐만 아니라 주구매지점도 동일한 현상이 발생

(일단 훈련용에 할당되지 않은 항목은 없긴 하지만...)

table(X_train_proc$주구매지점)
>
    강남점     관악점     광주점     노원점     대구점     대전점     동래점     미아점     본  점   부산본점     부평점     분당점     상인점 센텀시티점     안양점   영등포점     울산점 
       126         48         97         91          9         66         57         68       1052        233         58        459          1          9         25        247          7 
    인천점     일산점     잠실점     전주점     창원점   청량리점     포항점 
        41        199        473          5          3         94         12 

table(X_validation_proc$주구매지점)
>
    강남점     관악점     광주점     노원점     대구점     대전점     동래점     미아점     본  점   부산본점     부평점     분당점     상인점 센텀시티점     안양점   영등포점     울산점 
        32          7         33         16          0         12          6         15        226         56          8         78          0          1          8         49          1 
    인천점     일산점     잠실점     전주점     창원점   청량리점     포항점 
         3         36         95          1          1         15          0 

 

ㅠㅠ 이러면 나가란데...

'스몰데이터'면 이런 것도 고민해야되는구나...싶다 ㅋㅋ

내일 해결책을 고민해봐야겠다 (제일 무식한 방법은 랜덤 시드값을 바꾸는 것일래나?)

 

[시리즈]

빅데이터분석기사 실기 제2유형 문제 풀이 예시 (1)

빅데이터분석기사 실기 제2유형 문제 풀이 예시 (2)

빅데이터분석기사 실기 제2유형 문제 풀이 예시 (3)

빅데이터분석기사 실기 제2유형 문제 풀이 예시 Final

반응형