프로그래밍

[R] 내부 평가를 이용한 분류 모델 성능 평가

RainIron 2021. 6. 5. 23:33
반응형

1. 분류 모델과 내부 평가

1) 분류 모델

- 특정 기준(정답)에 의해 분석 대상을 특정 개수의 집단으로 분류하는 예측 모형

- 학습된 모델을 통해, 입력된 값을 미리 정해진 결과로 분류해주는 모델

 

2) 내부 평가

- 통계 분석 과정상 당연히 거쳐야 하는 과정을 제대로 이행하는지 여부에 중점을 둠

- 정확성, 안정성, 적합성, 객관성 등의 세부 평가 지표에 따라 평가

  -> 세부 지표 중 평가에 활용할 지표를 통상적 기준에 의해 선택하여 활용

 

3) 분류 모델의 종류

구분 정의
다중 판별 분석 집단 간의 차이를 의미있게 설명해 줄 수 있는 독립변수들을 찾아내고 이들의 선형결합으로 판별식을 만들어 내어 분류하고자 하는 대상들이 속하는 집단을 찾아내는 기법
로지스틱 회귀분석 독립변수의 선형결합을 이용해 사건의 발생가능성을 예측하는데 사용되는 기법
신경망 분석 수학적 모델로서 시스템이 상호 연결되어 네트워크를 형성할 때 이를 인간의 신경망처럼 분석하는 기법
사례 기반 추론 과거의 사례를 상기하여 이를 추론에 이용하는 기법
의사 결정 나무 의사결정 규칙을 도표화하여 관심대상이 되는 집단을 몇 개의 소집단으로 분류하거나 예측을 수행하는 계량적 분석 기법

 

4) 내부 평가 기준

- 적합성(안정성): 모형 적합도를 판단하기 위한 기준, 분류기준값(Cut-off Value), ROC 곡선 활용

- 정확성(객관성): 모델에 따라 분류된 데이터가 얼마나 정확하게 분류되었는지를 판단하는 지표, 예측 오차, 교차 유효성 검사, 혼동 행렬 등이 사용

 

2. 데이터 셋의 분류와 활용

* 교차 유효성 검사(교차 검증): 검증 데이터 셋을 이용한 분류 모델 성능 평가

- 전체 데이터를 검증 데이터 셋과 훈련 데이터 셋을 분류한 후, 훈련 데이터로 학습을 시키고 검증 데이터로 정확도를 측정하는 방법

- 훈련 데이터(70%), 검증 데이터(30%)

- 데이터를 분석자가 임의로 구분하므로 적합하지 못한 분류를 할 수 있음

  -> 모델의 과적합을 방지하고 적절한 학습 반복 수 찾기

 

3. 모델 평가의 절차와 과정

* 과정

단계 1 - 데이터 특성에 따른 분류 기법 적용
- 모형 생성
단계 2 - 예측 오차, 교차유효성, 혼동 행렬 이용 정확도 판단
- 데이터 셋 분류를 통한 반복 횟수 결정 및 모델 구조화
단계 3 - Cut-off Value, ROC 곡선을 통한 적합도 판단
- 최종 모형 설정

 

4. R 제공 Titanic 활용하여 분류 모델 평가 절차 수행

# R 제공 데이터 Titanic 사용
install.packages('functional')
install.packages('ROCR')
library(functional) # 데이터 전처리 패키지 
library(ROCR) # ROC 곡선 패키지
pivot.titanic <- as.data.frame(Titanic)

# Group 별 value 확인
pivot.titanic

각 Class, Sex, Age, Survied 별로 구분하여 Freq를 출력

# 데이터 셋 형태 변환(data preprocessing) - 1명당 1행으로 배치
attach(pivot.titanic) # 변수명에 대해 접근이 가능하게 함
Titanic.class <- c()
Titanic.sex <- c()
Titanic.age <- c()
Titanic.survived <- c()

# 각 행별 데이터를 추출하여 입력
for(i in 1:nrow(pivot.titanic)){
  n.rep <- functional::Curry(rep, times = Freq[i])
  Titanic.class <- append(Titanic.class, n.rep(as.character(Class[i])))
  Titanic.sex <- append(Titanic.sex, n.rep(as.character(Sex[i])))
  Titanic.age <- append(Titanic.age, n.rep(as.character(Age[i])))
  Titanic.survived <- append(Titanic.survived, n.rep(as.character(Survived[i])))
}
detach(pivot.titanic)
# 데이터 프레임으로 제작
Titanic <- data.frame(Idx = 1:length(Titanic.class),
                      Class = Titanic.class,
                      Sex = Titanic.sex,
                      Age = Titanic.age,
                      Survived = Titanic.survived)
                      
 Titanic

2001개의 데이터가 데이터프레임으로 구성되었다.

summary(Titanic)

# 각 클래스들의 비율을 맞춰 표본을 추출하기 위해 층화추출
sampling.info <- aggregate(Freq ~ Class + Sex + Age, pivot.titanic, sum)
sampling.info

# 검증용 데이터, 훈련용 데이터 추출(70:30)
test.ratio <- 0.7

test.idx <- c()

for(i in 1:nrow(sampling.info)){
  target.row <- sampling.info[i, ]
  key <- target.row[1:3]
  target.rows.idx <- merge(x = key, y = Titanic, by = c('Class', 'Sex', 'Age'))$Idx
  test.idx <- append(test.idx, sample(target.rows.idx, target.row$Freq * test.ratio))
}

test <- Titanic[test.idx, ]
train.idx <- setdiff(Titanic$Idx, test.idx)
train <-Titanic[train.idx, ]
summary(train)

summary(test)

train$Survived <- ifelse(train$Survived == 'No', 0, 1)
test$Survived <-ifelse(test$Survived == 'No', 0, 1)
# 로지스틱 회귀분석에서 종속변수가 숫자형으로 계산되어야 하기 때문에, No는 0으로 Yes는 1로 치환해준다.

# 로지스틱 회귀분석(결과값이 0 or 1로 분류)
model <- glm(Survived ~ Class + Sex + Age, family = 'binomial', data = train)

summary(model)
# 변수의 Estimate를 보면 -일수록 죽을 확률이 높은 변수
# ex) SexMale의 경우 Estimate가 -2.1596으로 Survived가 No인 0으로 수렴하게 하기 때문에 죽을 확률이 높은 변수라고 해석할 수 있다.

# ROC 곡선과 스코어 테이블 생성
require(ROCR)
prob <- predict(model, newdata = test, type = 'response')
labeled.score <- merge(Titanic, data.frame(Idx = as.integer(names(prob)), score = prob), by = c('Idx'))

pred <- prediction(prob, test$Survived)
roc <- performance(pred, measure = 'tpr', x.measure = 'fpr')
# tpr: 민감도
# fpr: 특이도

plot(roc, col = 'red') # ROC 곡선 출력
legend('bottomright', c('base', 'logistic'), col = 1:2, lty = 2:1) # 범례
abline(a = 0, b = 1, lty = 'dotted')

# AUC 결과
auc <- performance(pred, measure = 'auc')
auc <- auc@y.values[[1]]
auc
# 모형의 성능: fair

 

(추가) data를 csv파일로 export

write.csv(labeled.score[with(labeled.score, order(-score)), ], file = 'titanic_logistic_score.csv')

 

반응형