일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Bestin
- Home Assistant
- 코스피
- Espressif
- Python
- 티스토리챌린지
- 현대통신
- 국내주식
- 월패드
- 힐스테이트 광교산
- 배당
- esp32
- SK텔레콤
- 공모주
- cluster
- MQTT
- 오블완
- raspberry pi
- 애플
- matter
- homebridge
- 매터
- 해외주식
- 홈네트워크
- 미국주식
- Apple
- ConnectedHomeIP
- 파이썬
- 나스닥
- RS-485
- Today
- Total
YOGYUI
빅데이터분석기사 실기 제2유형 문제 풀이 예시 (3) 본문
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
이제 몇몇 머신러닝 알고리즘들에 대해 다음 프로세스를 수행해보자
- 훈련용 데이터 X_train_proc, y_train으로 학습
- 검증용 데이터 X_validation_proc, y_validation으로 분류 성능 검토
- 모델간 분류 성능 비교
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유형 문제 풀이 예시 (3)
'Study > 자격증' 카테고리의 다른 글
제2회 빅데이터분석기사 실기시험 유의사항 (0) | 2021.06.14 |
---|---|
빅데이터분석기사 실기 제2유형 문제 풀이 예시 Final (7) | 2021.06.13 |
빅데이터분석기사 실기 제2유형 문제 풀이 예시 (2) (0) | 2021.06.11 |
빅데이터분석기사 실기 제2유형 문제 풀이 예시 (1) (7) | 2021.06.11 |
빅데이터분석기사 실기 예시문제 유형 분석 (0) | 2021.05.12 |