노센스와 함께하는 데이터 분석

데이터과학자, '현장에서 바로 써먹는' 시리즈 저자

(R) 데이터 분석 실습

(R) 빅데이터분석기사 실기 작업형2 체험하기 코드

노센스 2021. 12. 2. 23:03

빅데이터분석기사 3회차 실기가 몇 일 남지 않은 상황에서 공부한 내용을 공유해 봅니다.

실시시험의 작업형2가 40점으로 가장 큰 배점을 차지하며, R이나 파이썬을 처음 접하는 분들께는 꽤나 어렵지 않을까 생각됩니다.

다행히도 한국데이터산업진흥원에서 실기시험을 체험해 볼 수 있는 링크를 제공해줘서 작업형2를 풀어보았습니다.
https://dataq.goorm.io/exam/116674/%EC%B2%B4%ED%97%98%ED%95%98%EA%B8%B0/quiz/3

 

구름EDU - 모두를 위한 맞춤형 IT교육

구름EDU는 모두를 위한 맞춤형 IT교육 플랫폼입니다. 개인/학교/기업 및 기관 별 최적화된 IT교육 솔루션을 경험해보세요. 기초부터 실무 프로그래밍 교육, 전국 초중고/대학교 온라인 강의, 기업/

edu.goorm.io


작업형2번은 분류(Classification) 문제인데요.
제가 데이터 전처리(파생변수 생성, 원핫인코딩 등)에서 다양한 방식을 시도해 보았는데 아무리해도 auc가 0.7을 못 넘겼었습니다.

아래 코드는 홀드아웃검정(hold-out validation) 및 K-폴드교차검정(k-fold cross validation)을 실시하지 않고, 단지, 훈련데이터셋의 예측값만 평가한 것으로 0.78~0.79 수준의 auc가 나왔습니다.

이렇게 성능이 향상된 가장 큰 요인은 오버샘플링(또는 업샘플링)이었습니다.

개인적으로 오버샘플링(Over Sampling)을 실제 업무에서는 과대적합(Overfitting) 우려로 사용하지 않는데, 해당 사례에서는 가장 큰 성능 향상을 나타냈습니다.
물론 test set의 gender 값을 제공하지 않기 때문에 정말로 과적합되어서 망했을 수도 있습니다. ^^;;

어쨌든 공부하는데 참고하실 수 있게 코드를 공유하오니 도움되셨으면 합니다.

# 출력을 원할 경우 print() 함수 활용 
# 예시) print(df.head()) 
# setwd(), getwd() 등 작업 폴더 설정 불필요 
# 파일 경로 상 내부 드라이브 경로(C: 등) 접근 불가 
X_test = read.csv('data/X_test.csv') 
X_train = read.csv('data/X_train.csv') 
y_train = read.csv('data/y_train.csv') 

## 데이터 전처리 ## 

# train 데이터셋 하나로 병합 
library(dplyr) 
train <- left_join(X_train, y_train, by = 'cust_id') 

# 결측치 처리 및 이상치 변환, 파생변수 생성 
train$환불금액 <- ifelse(is.na(train$환불금액) == 'TRUE', 0, train$환불금액) 
train$총구매액 <- ifelse(train$총구매액 <0, 0, train$총구매액) 
train$최대구매액 <- ifelse(train$최대구매액 <0, 0, train$최대구매액) 
train$최초구매액 <- train$총구매액 + train$환불금액 
train$최대구매액비율 <- train$최대구매액/train$최초구매액 
train$환불금액비율 <- train$환불금액/train$최초구매액 
X_test$환불금액 <- ifelse(is.na(X_test$환불금액) == 'TRUE', 0, X_test$환불금액) 
X_test$총구매액 <- ifelse(X_test$총구매액 <0, 0, X_test$총구매액) 
X_test$최대구매액 <- ifelse(X_test$최대구매액 <0, 0, X_test$최대구매액) 
X_test$최초구매액 <- X_test$총구매액 + X_test$환불금액 
X_test$최대구매액비율 <- X_test$최대구매액/X_test$최초구매액 
X_test$환불금액비율 <- X_test$환불금액/X_test$최초구매액 
train$gender <- as.factor(train$gender) 

# gender 데이터 불균형으로 인해 오버샘플링 실시 
library(caret) 

# 첫번째 열이 cust_id라 제외 
train <- train[,-1] 

train_up <- upSample(train[,-10], train[,10], list = F, yname = 'gender') 
tr_x <- train_up[,c(1,2,3,6,7,8,9,10,11,12)] 
tr_y <- train_up[,13] 
tr_y <- as.data.frame(tr_y) 
names(tr_y)[1] <- 'gender' 

# 한쪽으로 치우친 데이터 분포라 standard scaling 실시 
tr_xs <- scale(tr_x, center = T, scale = T) 
te <- X_test[,-c(1,5,6)] 
te_s <- scale(te, center = T, scale = T) 

# train 데이터 셋은 다시 하나의 데이터프레임으로 합침 
tr_s <- cbind(tr_xs, tr_y) 

## 모델링 ## 

# 보편적으로 높은 성능을 나타내는 랜덤포레스트 이용 
library(randomForest) 
model.rf <- randomForest(gender ~., data = tr_s, mtry = 3, ntree = 600) 

# train 데이터 셋 성능 확인(auc 0.78 ~ 0.79 수준) 
library(pROC) 
roc(tr_s$gender, as.numeric(model.rf$predicted)) 

# 원래는 train 데이터 셋을 train과 validation으로 한 번 더 분할해 
# hold out validation 또는 k-fold cross validation을 해줘야하나 
# 시간 절약 및 test 결과(미공개)와 비교해볼 수 없기 때문에 별도 실시하지 않음 

## 예측 ## 

# test 데이터 셋 예측 실시 
gender_pred <- predict(model.rf, newdata = te_s, type = "class") 

## 결과도출 ## 

# cust_id와 예측한 값(gender_pred) 하나의 데이터프레임으로 합침 
result <- cbind(as.data.frame(X_test[,1]),as.data.frame(gender_pred)) 

# 열이름 변경 
names(result) <- c('cust_id', 'gender') 

## 결과제출 ## 

write.csv(result, '003000000.csv', row.names=F)