pbj0812의 코딩 일기

[통계학] PYTHON 을 통한 AUPRC 구현 및 sklearn 과 비교 본문

Science/통계학

[통계학] PYTHON 을 통한 AUPRC 구현 및 sklearn 과 비교

pbj0812 2020. 11. 12. 22:15

0. 목표

 - PYTHON 을 통한 AUPRC 구현 및 sklearn 과 비교

1. 스크래치 실습

 1) library 호출

import pandas as pd
import matplotlib.pyplot as plt

 2) 데이터 생성

index = [i for i in range(1, 21)]
label = ['p', 'p', 'n', 'p', 'p', 'p', 'n', 'n', 'p', 'n', 'p', 'n', 'p', 'n', 'n', 'n', 'p', 'n', 'p', 'n']
probability = [0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.3, 0.1]

 3) 데이터프레임화

data = pd.DataFrame({'index' : index, 'label' : label, 'probability' : probability})

 4) Precision, Recall 계산 모듈

  - 정밀도(precision) : 분류기가 양성 샘플이라고 분류한 것 중에서 실제 양성 샘플인 것의 비율

  - 재현율(recall) : 실제 양성 샘플인 것 중에서 분류기가 정확히 분류해 낸 양성 샘플의 비율

# inp1 : data
def PR(inp1):
    Precision = []
    Recall = []
    P = len(inp1[inp1['label'] == 'p'])
    N = len(inp1[inp1['label'] == 'n'])
    for i in inp1['probability']:
        # precision
        tmp_p = data[data['probability'] >= i]
        TP = len(tmp_p[tmp_p['label'] == 'p'])
        tmp_precision = TP/len(tmp_p)
        tmp_recall = TP/P
        Precision.append(tmp_precision)
        Recall.append(tmp_recall)
    return Precision, Recall

 5) Precision, Recall 계산

Precision, Recall = PR(data)

 6) AUPRC 계산

  - 사다리꼴의 넓이 계산

AUPRC_Precision = [0] + Precision
AUPRC_Recall = [0] + Recall

AUPRC = 0
for i in range(1, len(AUPRC_Precision)):
    tmp_AUPRC = (AUPRC_Precision[i - 1] + AUPRC_Precision[i]) * (AUPRC_Recall[i] - AUPRC_Recall[i - 1]) / 2
    AUPRC += tmp_AUPRC

 7) 그림 그리기

fig = plt.figure()
fig.set_size_inches(15, 15)
plt.plot(Recall, Precision)
plt.fill_between(Recall, Precision, 0, facecolor="red", alpha=0.2)
plt.xlabel("Recall", fontsize = 24)
plt.ylabel("Precision", fontsize = 24)
for i in range(len(data['probability'])):
    plt.text(Recall[i], Precision[i], data['probability'][i], fontsize = 18)
# AUPRC 필기
plt.text(Recall[-1]/2, Precision[-1]/2, 'AUPRC : ' + str(AUPRC), fontsize = 24)

  - 결과

2. sklearn 사용

 1) library 호출

import numpy as np
from sklearn.metrics import average_precision_score
from sklearn.metrics import precision_recall_curve

 2) 데이터 변환 모듈

def str2num(inp):
    if 'p' in inp:
        return 1
    else:
        return 0

 3) 데이터 변환

data['label_int'] = data.apply(lambda x : str2num(x["label"]), axis = 1)

  - 결과

 4) precision, recall 계산

  - 구현한 방법과 반대로 계산

  - 이 때 thresholds 는 19개만 반환

precision, recall, thresholds = precision_recall_curve(data['label_int'], data['probability'])

   - precision : [0.52631579 0.5 0.52941176 0.5 0.53333333 0.57142857 0.61538462 0.58333333 0.63636364 0.6 0.66666667. 0.625 0.71428571 0.83333333 0.8 0.75 0.66666667 1. 1. 1. ]

  - recall : [1. 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.6 0.6 0.5 0.5 0.5 0.4 0.3 0.2 0.2 0.1 0. ]

  - thresholds : [0.3 0.33 0.34 0.35 0.36 0.37 0.38 0.39 0.4 0.505 0.51 0.52 0.53 0.54 0.55 0.6 0.7 0.8 0.9 ]

 5) 리스트 뒤집기

precision = list(precision)
recall = list(recall)
thresholds = list(thresholds)

precision.reverse()
recall.reverse()
thresholds.reverse()

 6) AUPRC 구현을 통한 계산

  - 0.719123790296391

AUPRC_Precision2 = [0] + precision
AUPRC_Recall2 = [0] + recall

AUPRC2 = 0
for i in range(1, len(AUPRC_Precision2)):
    tmp_AUPRC2 = (AUPRC_Precision2[i - 1] + AUPRC_Precision2[i]) * (AUPRC_Recall2[i] - AUPRC_Recall2[i - 1]) / 2
    AUPRC2 += tmp_AUPRC2
    
print(AUPRC2)

 7) sklearn 을 통한 계산

  - 0.7357475805927818

sklearn_AUPRC = average_precision_score(data['label_int'], data['probability'])
print(sklearn_AUPRC)

 8) 그림 그리기

  - thresholds 가 19개 밖에 없기에 임의로 앞에 1을 넣어줌

thresholds = [1] + thresholds

fig = plt.figure()
fig.set_size_inches(15, 15)
plt.plot(recall, precision)
plt.fill_between(recall, precision, 0, facecolor="red", alpha=0.2)
plt.xlabel("recall", fontsize = 24)
plt.ylabel("precision", fontsize = 24)
for i in range(len(thresholds)):
    plt.text(recall[i], precision[i], thresholds[i], fontsize = 18)
# AUPRC 필기
plt.text(recall[-1]/2, precision[-1]/2, 'AUPRC : ' + str(sklearn_AUPRC), fontsize = 24)

   - 결과

3. 참고

 - [Python] 리스트(배열) 순서 거꾸로 뒤집기

 - sklearn.metrics.precision_recall_curve

 - [ Python ] Pandas Lambda, apply를 활용하여 복잡한 로직 적용하기

 - sklearn.metrics.average_precision_score

Comments