본문 바로가기

Study/class note

머신러닝 / 민감도와 특이도, 정밀도와 재현율, F-1 score, ROC곡선

ㅇ 기계의 성능을 확인하는 방법

1. 정확도

                         TP + TN

정확도 = ------------------------------

                 TP + TN + FP + FN

 

2. 민감도와 특이도

3. 정밀도와 재현율

4. 카파통계량

            (Pr(a) - Pr(e)) 

kappa = ---------------

              (1-Pr(e))

 

5. ROC 곡선

6. F1 score

 

 

81 민감도와 특이도

유용한 분류기를 찾으려면 보통 지나치게 보수적인 예측과 지나치게 공격적인 예측사이에 균형이 필요.

보수적인 예측과 공격적인 예측에 대한 것을 정하는 기준이 되는 정보가 민감도와 특이도.

 

- 민감도 : 실제로 "긍정"인 범주 중에서 "긍정"으로 올바르게 예측한 비율

ex) 실제로 코로나 환자를 코로나 환자로 잘 예측한 사람의 비율

  예측
실제 TN FP
FN TP

                                     TP 

민감도(sensitivity) = ----------------------   = 정확하게 맞춘 예측값 / 실제 값

                                 TP + FN

TP : (관심범주를) 관심범주로 잘(True) 예측한 것

FN : (관심범주를) 관심범주가 아닌 것을 잘못(False) 예측 한 것

 

 

- 특이도 : 실제로 '부정'인 범주중에서 '부정'으로 올바르게 예측한(TN) 비율

ex) 실제 코로나가 아닌 사람을 코로나 음성으로 잘 예측한 비율

                                     TN

특이도(specifity) = ----------------------   = 정확하게 맞춘 예측값 / 실제 값

                                 TN + FP

TN : (관심범주가 아닌 것을) 관심범주가 아닌 것으로 잘(True) 예측한 것

FP : (관심범주가 아닌 것을) 관심범주로 잘못(False) 예측한 것

 

민감도와 특이도는 카파통계량처럼 0 ~ 1까지의 범위에 있으며, 값이 1에 가가울수록 바람직하나 실제로는 한쪽이 높으면 한쪽이 낮아져서 둘 다 높게 맞출수가 없음.

 

만약 유방암을 예측하는 머신러닝 모델을 여러개 만들어놓고 그 중에 하나를 선택해야한다면

  KNN 모델 의사결정트리 신경망
정확도 99% 99% 99%
카파통계량 0.92 0.91 0.91
민감도 0.6 0.7 0.7
특이도 0.5 0.4 0.5

이런 방식으로 비교하는데 굳이 선택을 하자면 민감도가 높고 특이도가 높은 신경망이 이 자료에선 가장 좋은 모델이라고 볼 수 있음.

민감도를 최고로 높게 맞춰놓고 그 중 특이도가 높은 것을 선택하면 됨. 민감도가 높으면 특이도가 다소 낮더라도 가치는 충분함.

 

 

예제1. sms_results.csv의 데이터로 스팸 분류기 모델의 민감도와 특이도를 R로 구하시오.

  예측
실제 TN(1203) FP(4)
FN(31) TP(152)

                                     TP                            152

민감도(sensitivity) = ----------------------   =  -------------------  = 0.8306011

                                 TP + FN                     152 + 31

                                     TN                         1203

특이도(specificity) = ----------------------   =   --------------------  = 0.996686

                                 TN + FP                    1203 + 4

 

# R
sms <- read.csv("c:\\data\\sms_results.csv", stringsAsFactors = TRUE)
head(sms)

library(caret)

#민감도
sensitivity(sms$predict_type, sms$actual_type, positive = 'spam')   #0.8306011

#특이도
sensitivity(sms$predict_type, sms$actual_type, negative = 'ham')  #0.996686

 

 

문제421. 아래의 혼동행렬에서 민감도와 특이도를 각각 구하시오

  예측
실제   False True
False 70 30
True 40 60

민감도 : 60 / 100 = 0.6

특이도 : 70 / 100 = 0.7

 

문제422. 위의 결과를 R코드를 이용해서 구하시오.

a <- as.table(matrix( c(60,30,40,70), byrow = T, nrow = 2, ncol = 2))
sensitivity(a)  # 민감도 0.6
specificity(a)  # 특이도 0.7

 

문제423. 유방암의 악성종양과 양성종약을 예측하는 knn 모델을 생성하고 민감도와 특이도를 구하시오.

# python
#1. 데이터 로드
import pandas as pd

wbcd = pd.read_csv("c:\\data\\wisc_bc_data.csv")
wbcd.head()

#2. 결측치 확인
wbcd.isnull().sum()

#3. 데이터 정규화
x = wbcd.iloc[:,2:]
y = wbcd['diagnosis']

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
x_scaled = scaler.fit_transform(x)

#4. 훈련데이터와 테스트 데이터 분리
from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x_scaled, y, test_size = 0.1, random_state = 1)

print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)  #(512, 30) (57, 30) (512,) (57,)

#5. 모델생성 및 훈련
from sklearn.neighbors import KNeighborsClassifier

model = KNeighborsClassifier(n_neighbors = 5)

model.fit(x_train,y_train)

#6. 모델예측
result = model.predict(x_test)
result

#7. 모델평가(정확도, 민감도, 특이도)
from sklearn.metrics import confusion_matrix

tn, fp, fn, tp = confusion_matrix(y_test, result).ravel()
print(tn, fp, fn, tp)  #43 0 1 13

accuracy = (tn+tp) / (tn+fn+fn+tp)  #0.9655172413793104 
sensitivity = tp / (tp+fn)   #0.9285714285714286
specificity = tn / (tn+fp)  #1.0

print(accuracy, sensitivity, specificity)

 

 

82 정밀도와 재현율 - p.456

정밀도 : '긍정'으로 예측한 것 중에서 실제로 '긍정'인 것의 비율 ( tp / (tp+fp) )

재현율 : 민감도와 동일 ( tp / (tp+fn) )

 

1. 소극적 예측 : 암이라고 판단하는 것 자체를 소극적으로 봐서 확실한 경우가 아니면 암으로 판단하지 않는 것.

                      ( 정밀도 ↑, 재현율 ↓)

2. 공격적 예측 : 조금만 의심이 가도 다 암이라고 판단함. ( 정밀도 ↓, 재현율 ↑)

 

ex) 병원에서는 주로 공격적 예측을 함. 암환자로 암환자로 판단했으면 잘한거고 혹시 암이 아닌 환자를 암환자로 예측했다 하더라도 나중에 검사를 통해 바로 잡을 수 있기 때문.

 

 

예제1. 아래의 스팸 분류기에 정밀도를 구하시오. precision = tp / (tp + fp)

  예측
실제 TN(1203) FP(4)
FN(31) TP(152)

precision = tp / (tp + fp) = 152 / (152 + 4) = 0.97

# R
sms <- read.csv("c:\\data\\sms_results.csv", stringsAsFactors = TRUE)
head(sms)

library(caret)
posPredValue(sms$predict_type, sms$actual_type, positive = 'spam')  #0.974359

 

문제424. 아래의 혼동행렬에서 정밀도를 구하시오. precision = tp / (tp + fp)

  예측
실제   False True
False 70 30
True 40 60

precision = tp / (tp + fp) = 60 / (30 + 60) = 0.6666667 

a <- as.table(matrix( c(60,30,40,70), byrow = T, nrow = 2, ncol = 2))
a 
posPredValue(a)  # 0.6666667

> matrix( tp, fp, fn, tn) 순서에 맞춰서 작성해야함.

 

문제425. 이번에는 파이썬으로 유방암의 악성과 양성종양을 예측하는 분류모델의 정밀도를 구하시오.

precision = tp / (tp + fp)

precision = tp / (tp + fp)  #1.0
print(precision)

 

 

83 F1 score - p458

정밀도와 재현율을 하나의 값으로 결합한 성능 척도를 F-척도라고 함.

F1 점수로 부르기도 함.

                 2 x 정밀도 x 재현율                    2 x tp

F - 척도 = --------------------------   =  ------------------------- 

                  재현율 + 정밀도                2 x tp + fp + fn  

 

 

예제1. 위에서 만든 유방암 knn모델의 F-척도를 구하시오.

from sklearn.metrics import confusion_matrix

tn, fp, fn, tp = confusion_matrix(y_test, result).ravel()

f1_score = (2*tp) / (2*tp + fp + fn)
print(f1_score)  #0.9629629629629629

 

문제426. (점심시간 문제) 아래의 혼동행렬의 f1 score를 구하시오

  예측
실제   False True
False 70 30
True 40 60
tn, fp, fn, tp = [70,30,40,60]
f1_score = (2*tp) / (2*tp + fp + fn)

print(f1_score)  # 0.631578947368421

f1 score작으면 잘못 판단한 False값들에 문제가 있다는 것.

FP와 FN값이 크다는 뜻으로 어떤 값이 문제가 있는지 확인하는 작업 필요.

 

 

84 ROC 곡선 - p459

= Receiver Operationg Characteristic

같은 데이터에 대한 여러 모델들의 성능을 시각화해서 비교해주는데 도움을 주는 그래프

다른 성능 척도인 민감도와 특이도를 숫자로만 보는게 아니라 시각화해서 여러 모델중에 가장 좋은 모델을 쉽게 찾게 해주는 그래프가 바로 ROC커브 그래프

TPR(True Positive Rate) : 참긍정율(민감도) : 관심범주를 관심범주로 잘 판정한 비율

FPR(False Positive Rate) : 거짓긍정율(1-특이도) : 관심범주가 아닌 것을 관심범주로(positive) 잘못(false) 판정한 비율

FPR은 낮추면서 TPR을 높일 수 있는 모형이 가장 좋은 모형이고 최대한 FPR을 낮추면서 TPR을 높일 수 있는 cut off 지점을 찾는 게 ROC그래프를 그리는 이유.

 

예제1. 독일 은행의 채무 불이행자를 예측하는 의사결정트리모델의 roc커브를 그리시오.

#1. 데이터 로드
credit <- read.csv("c:\\data\\credit.csv", stringsAsFactors = T)
head(credit)  #label 마지막 컬럼 

#2. 결측치 확인
colSums(is.na(credit))

nrow(credit)
ncol(credit)

#3. 훈련데이터 테스트 데이터 분리
library(caret)
set.seed(1)
k <- createDataPartition(credit$default, p = 0.9, list = F)
train_data <- credit[k,]
test_data <- credit[-k,]

nrow(train_data) #900
nrow(test_data) #100

#4. 모델생성 및 훈련
library(C50)
credit_model <- C5.0(train_data[, -17], train_data[,17])

#5. 모델예측
result <- predict(credit_model, test_data[,-17])
result

#6. 모델 평가 - 정확도
sum(result == test_data[,17]) / length(test_data[,17])  #0.67

#7. ROC곡선
credit_test_prob <- predict(credit_model, test_data[,-17], type = "prob")
credit_test_prob  # 각각의 분류 확률이 나옴

credit_results <- data.frame(actual_type = test_data[,17], #실제값
                             predict_type = result,  #예측값
                             prob_yes = round(credit_test_prob[,2], 5),  #yes일 확률
                             prob_no = round(credit_test_prob[,1],5) )  #no일 확률
credit_results


#정확도
sum(credit_results$actual_type == credit_results$predict_type) / length(credit_results$actual_type)
#민감도
library(caret)
sensitivity(credit_results$predict_type, 
            credit_results$actual_type, 
            positive = 'yes')  #0.2666667
#특이도
specificity(credit_results$predict_type,
            credit_results$actual_type,
            negative = 'no')  #0.8428571
#정밀도
posPredValue(credit_results$predict_type, 
             credit_results$actual_type,
             positive = 'yes')  #0.4210526
#재현율 = 민감도와 동일

#ROC곡선
install.packages("ROCR")
library(ROCR)

pred <- prediction(predictions = credit_results$prob_yes,
                   labels = credit_results$actual_type)
perf <- performance(pred, measure = 'tpr', x.measure = 'fpr')

plot(perf, main = 'ROC 커브', col = 'blue', lwd = 2)

#대각선 출력
abline(a = 0, b = 1, lwd = 2, lty = 2)

pred <- prediction(predictions = 관심범주의 확률, labels = 실제정답)

: ROC커브를 그리기 위한 데이터 포인트 생성

perf <- performance(pred, measure = 'tpr', x.measure = 'fpr')

: roc커브의 x축인 fpr, y축인 tpr에 해당되는 실제 데이터 포인트 26개가 생성됨

a = 0, b = 1, lwd = 2, lty = 2

: a는 직선의 절편, b는 기울기, lwd는 선의 굴기, lty는 점선 선택

+)  ROC곡선 더 간단하게 그리는 방법

from sklearn.metrics import plot_roc_curve
plot_roc_curve(model, x_test, y_test)

https://ichi.pro/ko/scikit-learneul-sayonghan-bunlyuleul-wihan-7-gaji-pilsu-seongneung-jipyoe-daehan-sil-yong-gaideu-50443865071680

반응형