내용 |
#####################################################
#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
#######################################################
|