Content

Board ID 323
Writer heojk
Write Date 2017-01-10 17:29:30
Subject 한화생명 데이터 분석 코드
Content ##################################################### #Step 9. 분석 종료 후 전체 데이터를 이용하여 분석 ##################################################### #Tools > Global Options > Code > Saving > #Default text encoding: UTF-8 ##################################################### rm(list=ls()) #작업 디렉토리 설정 setwd("E:/R_Project/Hanwha/Workplace") ##################################################### #원본 데이터 읽기 ##################################################### data_cust <- read.csv("Data/BGCON_CUST_DATA.csv", header=TRUE, sep=",", encoding="CP949", fileEncoding="UCS-2") data_claim <- read.csv("Data/BGCON_CLAIM_DATA.csv", header=TRUE, sep=",", encoding="CP949", fileEncoding="UCS-2") data_cntt <- read.csv("Data/BGCON_CNTT_DATA.csv", header=TRUE, sep=",", encoding="CP949", fileEncoding="UCS-2") data_fmly <- read.csv("Data/BGCON_FMLY_DATA.csv", header=TRUE, sep=",", encoding="CP949", fileEncoding="UCS-2") data_fpinfo <- read.csv("Data/BGCON_FPINFO_DATA.csv", header=TRUE, sep=",", encoding="CP949", fileEncoding="UCS-2") ##################################################### #사기여부가 저장되어 있는 데이터를 이용 ##################################################### cust_all <- data_cust nrow(cust_all) #22400 ##################################################### #데이터 전처리, NA, NULL 값 처리 등... ##################################################### #나이를 연령대로 변환 age_to_gen <- function(row) { row = floor(row/10) } cust_all$AGE <- sapply(cust_all$AGE, age_to_gen) #Y는 1으로 N은 0으로 변환 yn_to_10 <- function(row) { if(row=="Y") row = 1 else if(row=="N") row = 0 else row = "" } cust_all$SIU_CUST_YN <- sapply(cust_all$SIU_CUST_YN, yn_to_10) cust_all$FP_CAREER <- sapply(cust_all$FP_CAREER, yn_to_10) #NA를 0으로 na_to_0 <- function(row) { if(is.na(row)) row = 0 else row = row } cust_all$RESI_TYPE_CODE <- sapply(cust_all$RESI_TYPE_CODE, na_to_0) cust_all$TOTALPREM <- sapply(cust_all$TOTALPREM, na_to_0) #지역을 코드로 변환 ctpr_to_code <- function(row) { if(row=="서울") row = 1 else if(row=="부산") row = 2 else if(row=="대구") row = 3 else if(row=="인천") row = 4 else if(row=="광주") row = 5 else if(row=="대전") row = 6 else if(row=="울산") row = 7 else if(row=="세종") row = 8 else if(row=="경기") row = 9 else if(row=="강원") row = 10 else if(row=="충북") row = 11 else if(row=="충남") row = 12 else if(row=="전북") row = 13 else if(row=="전남") row = 14 else if(row=="경북") row = 15 else if(row=="경남") row = 16 else if(row=="제주") row = 17 else row = 0 } cust_all$CTPR <- sapply(cust_all$CTPR, ctpr_to_code) cust_all$CTPR <- unlist(cust_all$CTPR) #MINCRDT, MAXCRDT NA를 0으로 변환 na_to_6 <- function(row) { if(is.na(row)) row = 6 else row = row } cust_all$MINCRDT <- sapply(cust_all$MINCRDT, na_to_6) cust_all$MAXCRDT <- sapply(cust_all$MAXCRDT, na_to_6) cust_all$CUST_INCM <- sapply(cust_all$CUST_INCM, na_to_0) cust_all$JPBASE_HSHD_INCM <- sapply(cust_all$JPBASE_HSHD_INCM, na_to_0) #substr("3.Hello", 1, 1) occp_grp_1_to_no <- function(row) { row = substr(row, 1, 1) if(row == "") return (0) else return (as.integer(row)) } cust_all$OCCP_GRP_1 <- sapply(cust_all$OCCP_GRP_1, occp_grp_1_to_no) cust_all$MATE_OCCP_GRP_1 <- sapply(cust_all$MATE_OCCP_GRP_1, occp_grp_1_to_no) #널스트링을 N으로, 결혼 유무에서 널스트링일 경우 N으로 nullstring_to_N <- function(row) { if(row == "N") row = "N" else if(row == "Y") row = "Y" else row = "N" } cust_all$WEDD_YN <- sapply(cust_all$WEDD_YN, nullstring_to_N) cust_all$WEDD_YN <- sapply(cust_all$WEDD_YN, yn_to_10) #데이터 임시 저장 write.csv(cust_all, "Modeling/cust_all.csv", row.names = FALSE) #임시 함수 제거 rm(age_to_gen) rm(yn_to_10) rm(na_to_0) rm(ctpr_to_code) rm(na_to_6) rm(occp_grp_1_to_no) rm(nullstring_to_N) ##################################################### #소득이 0인 사람의 데이터를 직업별 평균 값으로 수정, (cust_incm_avg_by_occp <- tapply(cust_all$CUST_INCM, cust_all$OCCP_GRP_1, mean)) (cust_incm_avg_by_occp <- round(cust_incm_avg_by_occp)) # 0 1 2 3 4 5 6 7 8 #1은 주부 #873 0 3803 3987 3894 3361 3573 2180 225 zero_to_mean <- function(occp, incm) { if(incm == 0) return (cust_incm_avg_by_occp[occp+1]) else return (incm) } #mapply(function, ...) cust_all$CUST_INCM <- mapply(zero_to_mean, cust_all$OCCP_GRP_1, cust_all$CUST_INCM) rm(zero_to_mean) rm(cust_incm_avg_by_occp) ##################################################### #평균 입원일수 #VLID_HOSP_OTDA의 고객별 평균 #고객 별 평균 입원 일 수 계산 #aggregate(d[, 3:4], list(d$Name), mean) hosp_day_per_cust <- aggregate(data_claim$VLID_HOSP_OTDA, list(data_claim$CUST_ID), mean) names(hosp_day_per_cust) <- c("CUST_ID", "HOSP_DAYS") hosp_day_per_cust$HOSP_DAYS <- round(hosp_day_per_cust$HOSP_DAYS) #CUST_ID를 기준으로 결합 cust_all <- merge(cust_all, hosp_day_per_cust) rm(hosp_day_per_cust) ##################################################### #청구횟수/가입상품수 #고객 별 청구 횟수 data_claim$CLAIM_COUNT <- 1 claim_count_per_cust <- aggregate(data_claim$CLAIM_COUNT, list(data_claim$CUST_ID), sum) names(claim_count_per_cust) <- c("CUST_ID", "CLAIM_COUNT") #CUST_ID를 기준으로 결합 cust_all <- merge(cust_all, claim_count_per_cust) #고객 별 가입 상품 수 data_cntt$CNTT_COUNT <- 1 cntt_count_per_cust <- aggregate(data_cntt$CNTT_COUNT, list(data_cntt$CUST_ID), sum) names(cntt_count_per_cust) <- c("CUST_ID", "CNTT_COUNT") #CUST_ID를 기준으로 결합 cust_all <- merge(cust_all, cntt_count_per_cust) cust_all$CLAIM_RATIO_BY_CNTT <- round((cust_all$CLAIM_COUNT / cust_all$CNTT_COUNT) * 100) ##################################################### #사고구분/청구사유 조합 table(data_claim$ACCI_DVSN, data_claim$DMND_RESN_CODE) # 1 2 3 4 5 6 7 9 #1 60 13351 7751 491 3761 8160 50 4 #2 58 7712 619 240 473 684 0 0 #3 471 40953 16063 171 16277 1551 119 1 #보험청구 사유 2-7, 1-9,2-9,3-9 분석 대상에서 제외 #install.packages("reshape") library(reshape) #cast() 함수를 사용하기 위함, melt함수의 반대 #고객아이디, 사고구분, 청구사유 조합 acci_dmnd_count <- table(data_claim$CUST_ID, data_claim$ACCI_DVSN, data_claim$DMND_RESN_CODE) acci_dmnd_count <- as.data.frame(acci_dmnd_count) #캐스트 하기 위해 마지막 열은 이름이value 이어야 함 names(acci_dmnd_count) <- c("CUST_ID", "ACCI_DVSN", "DMND_RESN_CODE", "value") head(acci_dmnd_count) acci_dmnd_count <- cast(data=acci_dmnd_count, CUST_ID ~ ACCI_DVSN + DMND_RESN_CODE, fun=sum) cust_all <- merge(cust_all, acci_dmnd_count) #보험청구 사유 2-7, 1-9,2-9,3-9 분석 대상에서 제외(다시 포함시키려고 주석처리 함) #cust_all <- cust_all[ ,!(colnames(cust_all) %in% c("2_7", "1_9", "2_9", "3_9"))] names(cust_all) write.csv(cust_all, "Modeling/cust_all_before_modeling.csv", row.names = FALSE) ##################################################### #데이터 탐색을 통한 변수 선택 후 분석에서 제외할 변수 제거 ##################################################### #drop OCCP_GRP_2 & MATE_OCCP_GRP_2 variable cust_all <- subset(cust_all, select=-c(OCCP_GRP_2, MATE_OCCP_GRP_2)) cust_all <- subset(cust_all, select=-c(MAX_PAYM_YM, MAX_PRM)) cust_all <- subset(cust_all, select=-CUST_RGST) cust_all <- subset(cust_all, select=-c(CHLD_CNT, LTBN_CHLD_AGE)) cust_all <- subset(cust_all, select=-c(DIVIDED_SET, RESI_COST, RESI_TYPE_CODE, TOTALPREM, MINCRDT, MAXCRDT, JPBASE_HSHD_INCM,CLAIM_COUNT, CNTT_COUNT)) #데이터 임시 저장 write.csv(cust_all, "Modeling/cust_all_before_modeling2.csv", row.names = FALSE) ##################################################### #데이터를 사기여부가 판별된 데이터와 그렇지 않은 데이터 분리 ##################################################### cust_all <- read.csv("Modeling/cust_all_before_modeling2.csv", header=TRUE) cust_train <- subset(cust_all, subset=!(cust_all$SIU_CUST_YN=="")) #Training set cust_train <- cust_train[order(cust_train$CUST_ID),] #트레이닝 셋 정렬 nrow(cust_train) #20607 cust_test <- subset(cust_all, subset=(is.na(cust_all$SIU_CUST_YN))) #Test set cust_test <- cust_test[order(cust_test$CUST_ID),] #테스트 셋 정렬 nrow(cust_test) #1793 write.csv(cust_train, "Modeling/cust_train.csv", row.names = FALSE) write.csv(cust_test, "Modeling/cust_test.csv", row.names = FALSE) ##################################################### #XGBoost를 이용한 분석(기본 정보를 이용한 분석) ##################################################### #install.packages('xgboost') library(xgboost) cust_train <- read.csv("Modeling/cust_train.csv", header=TRUE) cust_test <- read.csv("Modeling/cust_test.csv", header=TRUE) #종속 변수가 맨 오른쪽으로 와야함 데이터 재구축 #트레이닝에는 라벨있어야 되고(가장 오른쪽에) cust_train <- cbind(subset(cust_train, select=-SIU_CUST_YN), subset(cust_train, select=SIU_CUST_YN)) #테스트에는 라벨 없어야됨 #cust_test_yn 변수는 예측 후 원본과 비교하기 위해서 임시 저장함 cust_test_yn <- subset(cust_test, select=c(CUST_ID, SIU_CUST_YN)) cust_test <- subset(cust_test, select=-SIU_CUST_YN) #사기자 여부 라벨 제거 #트레이닝 셋과 테스트 셋에서 고객 아이디 열 제거 cust_train <- subset(cust_train, select=-CUST_ID) cust_test <- subset(cust_test, select=-CUST_ID) y <- cust_train[,ncol(cust_train)] #트레이닝 셋의 사기자 여부에 해당하는 열 table(y) #트레이닝 셋의 일반인가 사기자 수 18801 1806 x <- subset(cust_train, select=-SIU_CUST_YN) #x는 분석하기 위한 데이터 nrow(x) #20607 x <- as.matrix(x) x <- matrix(suppressWarnings(as.numeric(x)), nrow(x), ncol(x)) #여러개로 분류 가능함 넘 클래스 숫자가 분류 숫자임 param <- list("objective" = "multi:softprob", "eval_metric" = "mlogloss", "num_class" = 2, #2개로만 분류 "nthread" = 8) # Run Cross Valication bst.cv <- xgb.cv(param=param, data=x[1:length(y),], nrounds=50, nfold = 3, label = y, missing=NaN) rm(bst.cv) # Train the model(모델 생성) bst_trained_model <- xgboost(param=param, data=x[1:length(y),], nrounds=60, label=y, missing=NaN) ##멀티용 예측임 #테스트 셋을 이용하여 예측 x_test <- as.matrix(cust_test) x_test <- matrix(suppressWarnings(as.numeric(x_test)), nrow(x_test), ncol(x_test)) predicted_data <- predict(bst_trained_model, x_test, missing=NaN) length(predicted_data)/2 #1793 nrow(cust_test) #1793 #2열짜리 매트릭스로 변환 predicted_data <- matrix(predicted_data, ncol=2, nrow=length(predicted_data)/2, byrow=TRUE) #두 열 중에 큰 값의 열을 반환, #두 범주로 나누어 예측했기 때문에 사기가 아니다와 사기이다 두 값이 #각각 V1열과 V2열에 저장되어 있음 predicted_yn <- max.col(predicted_data) #신경망 출력으로 나온 클래스 라벨 #예측한 데이터가 정상인은 1, 사기자는 2이므로 이것을 정상인은 0, 사기자는 1로 바꿈 #제출해야 할 데이터가 정상인은 0, 사기자는 1 형식 또는 정상인은 N, 사기자는 Y 형식임 yn12_to_01 <- function(row) { if(row == 1) row = 0 else if(row == 2) row = 1 } predicted_yn <- sapply(predicted_yn, yn12_to_01) rm(yn12_to_01) #테스트셋에서 뽑아낸 원래의 값과 예측한 값을 합침 result <- cbind(cust_test_yn, predicted_yn) #정답 불러오기. answer <- read.csv("answer.csv", header=TRUE) result$SIU_CUST_YN <- answer$SIU_CUST_YN #결과 저장 write.csv(result, "Modeling/result.csv", row.names = FALSE) ##################################################### #테스트셋의 원본 데이터와 예측한 데이터를 이용한 검정 통계량 출력 ##################################################### result <- read.csv("Modeling/result.csv", header=TRUE) temp <- table(result$SIU_CUST_YN, result$predicted_yn) temp temp[1,1] #True Negative temp[1,2] #False Positive temp[2,1] #False Negative temp[2,2] #True Positive fun_fmeasure <- function(table){ precision <- table[2,2]/(table[1,2]+table[2,2]) # TP/(FP+TP) recall <- table[2,2]/(table[2,1]+table[2,2]) # TP/(FN+TP) return(2*precision*recall/(precision+recall)) } #F-measure : Precision 과 Recall의 조화 평균 fun_fmeasure(temp) #0.5461847 ##################################################### #의사결정나무 출력 ##################################################### #install.packages("rpart") library(rpart) decision_tree_data <- rpart(predicted_yn ~ ., data=cust_test) decision_tree_data plot(decision_tree_data, compress=TRUE, margin=.2) text(decision_tree_data, cex=0.8) ####################################################### #Step 9. END #######################################################
File Script_Step9_Modeling_20161226.R (14,120byte)