Machine Learning Academy · 강의

실전에서의 정밀도, 재현율, F1 점수

정밀도와 재현율을 계산하고, 정밀도와 재현율의 상충 관계를 이해하며, 불균형한 실제 작업에 알맞은 평가 지표를 선택합니다.

레슨 4/413개 단계

실전에서의 정밀도, 재현율, F1 점수은(는) CoddyKit의 무료 Machine Learning Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Machine Learning Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Machine Learning Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

정밀도-재현율 체계

클래스의 분포가 불균형하거나 오류 유형마다 비용이 다를 때는 모델이 양성 클래스를 어떻게 처리하는지에 특히 초점을 맞춘 지표가 필요합니다. 정밀도와 재현율은 이러한 역할을 하는 상호 보완적인 두 지표입니다.

정밀도와 재현율을 함께 사용하면 참 음성이 많더라도 왜곡되지 않고 양성 클래스에 대한 분류기의 동작을 종합적으로 파악할 수 있습니다. 양성 클래스는 드물지만 매우 중요한 사기 탐지, 질병 선별 검사, 콘텐츠 관리 등의 영역에서 이는 특히 중요합니다.

정밀도: 양성 예측의 품질

정밀도는 다음 질문에 답합니다. 모델이 양성으로 예측한 모든 사례 중 실제로 양성이었던 사례의 비율은 얼마인가?

정밀도 = TP / (TP + FP)

정밀도가 높다는 것은 오탐이 적다는 뜻입니다. 정밀도가 0.99인 스팸 필터는 스팸 폴더로 분류된 이메일의 99%가 실제 스팸이며, 정상적인 이메일이 잘못 분류되는 경우가 거의 없다는 의미입니다. 그러나 정밀도만으로는 실제 스팸 이메일을 얼마나 놓쳤는지 알 수 없습니다. 이메일 하나만 스팸으로 표시했고 그 이메일이 실제 스팸이었다면, 수천 개의 스팸 이메일을 놓쳤더라도 정밀도는 1.0입니다.

from sklearn.metrics import precision_score
from sklearn.metrics import confusion_matrix
import numpy as np

y_true = np.array([1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0])
y_pred = np.array([1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0])

cm = confusion_matrix(y_true, y_pred)
TN, FP, FN, TP = cm.ravel()

precision_manual = TP / (TP + FP)
precision_sklearn = precision_score(y_true, y_pred)

print(f'TP={TP}, FP={FP}, FN={FN}, TN={TN}')
print(f'Precision (manual): {precision_manual:.3f}')
print(f'Precision (sklearn): {precision_sklearn:.3f}')

재현율: 실제 양성의 포착 범위

재현율(민감도 또는 참 양성률이라고도 함)은 다음 질문에 답합니다. 실제 양성인 모든 사례 중 모델이 정확히 식별한 사례의 비율은 얼마인가?

재현율 = TP / (TP + FN)

재현율이 높다는 것은 놓친 양성이 적다는 뜻입니다. 재현율이 0.95인 암 선별 검사는 실제로 암이 있는 환자의 95%를 찾아내며, 5%만 놓칩니다. 그러나 재현율만으로는 건강한 환자를 얼마나 잘못 양성으로 판정했는지 알 수 없습니다. 양성을 놓쳤을 때의 비용(거짓 음성)이 매우 큰 경우에는 높은 재현율이 필수적입니다.

from sklearn.metrics import recall_score
import numpy as np

y_true = np.array([1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0])
y_pred = np.array([1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0])

TP = ((y_pred == 1) & (y_true == 1)).sum()
FN = ((y_pred == 0) & (y_true == 1)).sum()

recall_manual = TP / (TP + FN)
recall_sklearn = recall_score(y_true, y_pred)

print(f'TP={TP}, FN={FN}')
print(f'Recall (manual): {recall_manual:.3f}')
print(f'Recall (sklearn): {recall_sklearn:.3f}')

정밀도-재현율의 상충 관계

정밀도와 재현율은 서로 상충합니다. 모든 사례를 양성으로 예측하면 재현율을 항상 1.0으로 높일 수 있지만, 그중 대부분이 거짓 양성이 되므로 정밀도는 급격히 낮아집니다. 반대로 매우 확신할 때만 양성으로 예측하면(임곗값이 매우 높으면) 정밀도는 향상되지만 실제 양성을 많이 놓쳐 재현율이 낮아집니다.

판정 임곗값을 변경하면 균형이 달라집니다. 임곗값을 낮추면 더 많은 사례를 양성으로 표시하므로 재현율은 높아지고 정밀도는 낮아집니다. 임곗값을 높이면 모델이 더 선별적으로 작동하므로 정밀도는 높아지고 재현율은 낮아집니다. 대부분의 실제 문제에서는 두 지표를 동시에 최대화하는 임곗값이 없습니다.

from sklearn.metrics import precision_score, recall_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import numpy as np

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
X_train_s = StandardScaler().fit_transform(X_train)
X_test_s = StandardScaler().fit_transform(X_test)

model = LogisticRegression(max_iter=1000)
model.fit(X_train_s, y_train)
scores = model.predict_proba(X_test_s)[:, 1]

for threshold in [0.3, 0.5, 0.7, 0.9]:
    y_pred = (scores >= threshold).astype(int)
    p = precision_score(y_test, y_pred, zero_division=0)
    r = recall_score(y_test, y_pred, zero_division=0)
    print(f'Threshold {threshold}: Precision={p:.3f}  Recall={r:.3f}')

F1 점수: 정밀도와 재현율의 균형

F1 점수는 조화 평균을 사용하여 정밀도와 재현율을 하나의 수치로 결합합니다.

F1 = 2 × (정밀도 × 재현율) / (정밀도 + 재현율)

조화 평균은 극단적인 불균형에 불이익을 줍니다. 정밀도가 0.9이고 재현율이 0.1인 모델의 F1은 0.5가 아니라 2×0.9×0.1/1.0 = 0.18입니다. 따라서 단순 평균보다 F1을 유리하게 조작하기가 훨씬 어렵습니다. 정밀도와 재현율이 모두 1.0일 때만 F1 = 1.0입니다.

from sklearn.metrics import f1_score
import numpy as np

# Compare two classifiers
clf_a_prec, clf_a_rec = 0.9, 0.5   # high precision, low recall
clf_b_prec, clf_b_rec = 0.7, 0.7   # balanced

def f1_from_pr(precision, recall):
    return 2 * precision * recall / (precision + recall)

f1_a = f1_from_pr(clf_a_prec, clf_a_rec)
f1_b = f1_from_pr(clf_b_prec, clf_b_rec)

print(f'Classifier A: P={clf_a_prec} R={clf_a_rec} F1={f1_a:.3f}')
print(f'Classifier B: P={clf_b_prec} R={clf_b_rec} F1={f1_b:.3f}')
print('\nClassifier B has better F1 despite lower precision.')

F-beta 점수: 정밀도와 재현율의 가중치 조정

F1 점수는 정밀도와 재현율을 똑같이 중요하게 취급합니다. Fβ 점수를 사용하면 재현율에 정밀도보다 β배 더 큰 가중치를 줄 수 있습니다.

Fβ = (1 + β²) × 정밀도 × 재현율 / (β² × 정밀도 + 재현율)

  • β = 1: 표준 F1(동일한 가중치)
  • β = 2 (F2): 재현율을 두 배 더 중요하게 취급합니다. 사례를 놓치는 것이 치명적인 암 선별 검사에 사용합니다.
  • β = 0.5 (F0.5): 정밀도를 두 배 더 중요하게 취급합니다. 오탐의 비용이 큰 스팸 필터에 사용합니다.
from sklearn.metrics import fbeta_score
import numpy as np

y_true = np.array([1, 0, 1, 1, 0, 0, 1, 0, 1, 0])
y_pred = np.array([1, 0, 1, 0, 1, 0, 1, 0, 0, 0])

# beta=1 (F1): equal weight
f1 = fbeta_score(y_true, y_pred, beta=1)
# beta=2: emphasise recall
f2 = fbeta_score(y_true, y_pred, beta=2)
# beta=0.5: emphasise precision
f_half = fbeta_score(y_true, y_pred, beta=0.5)

print(f'F1   (beta=1.0): {f1:.3f}')
print(f'F2   (beta=2.0): {f2:.3f}  <- emphasises recall')
print(f'F0.5 (beta=0.5): {f_half:.3f}  <- emphasises precision')

정밀도-재현율 곡선

하나의 임곗값에서 평가하는 대신, 정밀도-재현율 곡선은 가능한 모든 임곗값에서 정밀도와 재현율의 관계를 그래프로 나타냅니다. 곡선의 형태를 보면 모델이 달성할 수 있는 최선의 상충 관계를 알 수 있습니다.

정밀도-재현율 곡선 아래 면적(PR-AUC)이 큰 모델은 오탐을 지나치게 많이 만들지 않으면서 양성을 더 잘 찾아냅니다. 양성 클래스가 드문 경우에는 ROC-AUC보다 PR-AUC를 선호합니다. PR-AUC는 참 음성이 많은 전체 집합의 영향을 받기보다 소수 클래스의 성능에 초점을 맞추기 때문입니다.

from sklearn.metrics import precision_recall_curve, average_precision_score
import matplotlib.pyplot as plt

# Get probability scores for positive class
scores = model.predict_proba(X_test_s)[:, 1]

precision_vals, recall_vals, _ = precision_recall_curve(y_test, scores)
ap = average_precision_score(y_test, scores)

plt.plot(recall_vals, precision_vals, 'b-', linewidth=2)
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title(f'Precision-Recall Curve (AP={ap:.3f})')
plt.grid(True, alpha=0.3)
plt.show()

거시 평균, 미시 평균, 가중 평균

다중 클래스 분류에서 scikit-learn은 정밀도, 재현율, F1에 대해 여러 유형의 평균을 보고합니다.

  • 거시 평균: 클래스별로 지표를 계산한 다음 가중치를 적용하지 않은 평균을 구합니다. 클래스의 크기와 관계없이 모든 클래스를 똑같이 취급합니다.
  • 가중 평균: 클래스별로 지표를 계산한 다음 각 클래스의 사례 수를 가중치로 사용해 평균을 구합니다. 전체 데이터 세트의 성능을 반영합니다.
  • 미시 평균: 모든 클래스의 TP/FP/FN을 합산한 다음 지표를 계산합니다. 정확도의 경우 전체 정확도와 같습니다.
from sklearn.metrics import classification_report
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

clf = DecisionTreeClassifier(max_depth=4)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)

print(classification_report(y_test, y_pred,
      target_names=['setosa', 'versicolor', 'virginica']))

문제에 맞는 지표 선택하기

지표를 선택하는 기준은 다음과 같습니다.

  • 클래스가 균형적이고 오류 비용이 동일함 → 정확도
  • 클래스가 불균형하고 FP 비용이 높음 → 정밀도(예: 스팸 필터 — 정상적인 이메일을 버리지 않도록 함)
  • 클래스가 불균형하고 FN 비용이 높음 → 재현율(예: 질병 선별 검사 — 아픈 환자를 놓치지 않도록 함)
  • FP와 FN 모두 비용이 크고 단일 지표가 필요함 → F1
  • FN의 비용이 FP보다 훨씬 큼 → F2(암 탐지, 조사할 수 있는 사기 탐지)
  • 모든 임곗값에서 평가해야 함 → PR-AUC 또는 ROC-AUC

특이도와 혼동 행렬의 완성

이진 분류기의 성능을 완전히 파악하려면 다음 두 가지 추가 지표가 필요합니다.

  • 특이도(참 음성률) = TN / (TN + FP): 실제 음성인 모든 사례 중 모델이 정확히 식별한 사례의 비율입니다. 특이도가 높다는 것은 오탐이 적다는 뜻입니다. 의료 검사에서는 민감도(재현율)와 함께 사용합니다.
  • 낙오율(거짓 양성률) = FP / (FP + TN): 특이도의 여집합입니다. 평가 지표 수업에서 살펴볼 ROC 곡선의 x축입니다.
import numpy as np
from sklearn.metrics import confusion_matrix

y_true = np.array([1, 0, 1, 1, 0, 0, 1, 0, 1, 0])
y_pred = np.array([1, 0, 1, 0, 1, 0, 1, 0, 0, 0])

cm = confusion_matrix(y_true, y_pred)
TN, FP, FN, TP = cm.ravel()

sensitivity = TP / (TP + FN)  # recall
specificity = TN / (TN + FP)
fpr         = FP / (FP + TN)  # false positive rate

print(f'Sensitivity (Recall):   {sensitivity:.3f}')
print(f'Specificity (TNR):      {specificity:.3f}')
print(f'False Positive Rate:    {fpr:.3f}')
print(f'Sensitivity + Specificity should be > 1 for a useful model')

사용자 지정 임곗값을 적용한 분류 보고서

기본 임곗값 0.5가 항상 최적인 것은 아닙니다. 가장 적합한 임곗값을 찾는 과정은 다음과 같습니다. 여러 임곗값에서 정밀도, 재현율, F1을 계산한 다음 문제와 관련된 지표를 최대화하는 임곗값을 선택합니다.

사기 탐지 상황에서는 재현율을 우선하기 위해 F2를 최대화할 수 있습니다. 콘텐츠 관리 시스템에서는 정상적인 콘텐츠가 잘못 삭제되는 것을 피하기 위해 정밀도를 최대화할 수 있습니다. precision_recall_curve 함수는 이 분석에 필요한 모든 데이터를 제공합니다.

import numpy as np
from sklearn.metrics import precision_recall_fscore_support

scores = model.predict_proba(X_test_s)[:, 1]
thresholds = np.arange(0.1, 0.95, 0.05)

best_f1, best_threshold = 0, 0.5
for t in thresholds:
    y_pred = (scores >= t).astype(int)
    p, r, f, _ = precision_recall_fscore_support(y_test, y_pred, average='binary', zero_division=0)
    if f > best_f1:
        best_f1, best_threshold = f, t
    print(f't={t:.2f}: P={p:.3f} R={r:.3f} F1={f:.3f}')

print(f'\nBest F1={best_f1:.3f} at threshold={best_threshold:.2f}')

빠른 확인

이번 수업에서 배운 Python을 활용한 머신 러닝 개념을 얼마나 이해했는지 확인해 보세요.

수업 요약

이번 수업에서는 정밀도가 양성 예측의 품질을 측정한다는 것(TP/(TP+FP)), 재현율이 실제 양성을 포착하는 범위를 측정한다는 것(TP/(TP+FN)), 그리고 F1 점수의 조화 평균이 두 지표의 균형을 맞추며 Fβ를 사용하면 애플리케이션의 오류 비용 구조에 따라 재현율이나 정밀도에 더 큰 가중치를 줄 수 있다는 것을 배웠습니다. 다음으로 모델 평가의 근본적인 질문을 다룹니다. 모델을 학습에 사용한 데이터로 평가하면 안 되는 이유와, 분리된 테스트 세트를 사용해 일반화 성능을 올바르게 추정하는 방법을 알아봅니다.

무료로 시작

AI 튜터와 함께 Python을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
30
레슨
120

자주 묻는 질문

“실전에서의 정밀도, 재현율, F1 점수” 강의는 무료인가요?

네 — “실전에서의 정밀도, 재현율, F1 점수” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Machine Learning Academy 강의 전체를 잠금 해제할 수 있습니다. Machine Learning Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“실전에서의 정밀도, 재현율, F1 점수”에서 뭘 배우나요?

정밀도와 재현율을 계산하고, 정밀도와 재현율의 상충 관계를 이해하며, 불균형한 실제 작업에 알맞은 평가 지표를 선택합니다. 브라우저에서 직접 실행하는 실습 코드로 Machine Learning Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Machine Learning Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Machine Learning Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“실전에서의 정밀도, 재현율, F1 점수” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Machine Learning Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Machine Learning Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 회귀에서 분류로: 임계값에 따른 결정
  2. 로지스틱 회귀와 시그모이드 함수
  3. 혼동 행렬 이해하기
  4. 실전에서의 정밀도, 재현율, F1 점수
← Machine Learning Academy(으)로 돌아가기