F1 Score로 불균형 분류 모델을 평가하는 방법

F1 Score의 조화평균 원리와 평균 방식, 임계값 최적화, 불균형 데이터 환경에서의 운영 기준을 정리한다.

2026-08-14 · 최초 발행 2025-10-14

정확도만으로는 부족한 분류 평가

불균형 데이터에서는 Accuracy가 모델 성능을 과대평가할 수 있다. F1 Score는 Precision(정밀도)과 Recall(재현율)을 함께 반영해 이런 착시를 줄이고, 도메인 편중을 완화하면서 운영 환경의 성능을 판단하기 위한 지표다.

수식은 다음과 같다.

F1 = 2 / (1/Precision + 1/Recall) = 2 × (Precision × Recall) / (Precision + Recall)

두 값의 조화평균이므로 Precision과 Recall 가운데 낮은 값의 영향이 크다. 한쪽만 높아도 F1은 낮게 나오며, 불균형 라벨 환경에서 Accuracy만으로 놓치기 쉬운 문제를 드러낸다.

Precision과 Recall 사이의 균형

조화평균은 산술평균보다 낮은 값에 더 큰 페널티를 준다. 따라서 Precision과 Recall의 균형을 평가하기에 적합하다. Recall이 0에 가까워지면 F1도 0으로 수렴하므로, 거짓 양성과 거짓 음성의 트레이드오프를 확인할 수 있다.

멀티클래스나 멀티라벨 문제에서는 집계 방식도 결과에 영향을 준다.

  • Macro F1은 클래스별 F1을 균등하게 평균내므로 소수 클래스의 영향이 커진다.
  • Weighted F1은 클래스별 F1에 샘플 비율 가중치를 적용한다. 실제 분포를 반영하지만 다수 클래스의 영향도 커진다.
  • Micro F1은 전역 TP/FP/FN을 집계한 뒤 계산하므로 표본 수가 큰 클래스 비중이 확대된다.

이진 분류에서는 결정 임계값을 조정해 Precision과 Recall의 균형을 바꿀 수 있다. PR 곡선에서 F1이 최대가 되는 지점을 선택할 수 있으며, 재현율을 더 우선해야 한다면 Fβ로 가중치를 조정한다.

불균형 데이터에서 확인할 점

F1 Score는 Accuracy보다 불균형에 강인하며 소수 클래스 성능을 반영한다. 클래스 가중, 샘플링, 임계값 튜닝과 함께 사용하면 효과가 커진다.

다만 True Negative는 반영하지 않는다. 정상 데이터가 다수인 문제가 중요한 경우에는 정보가 손실될 수 있다. 확률 보정(calibration) 품질도 직접 보여주지 않으므로 AUC-PR, Brier score 같은 보조 지표를 함께 보는 편이 낫다.

운영 환경에서의 활용

이상거래 탐지나 보안 알림처럼 소수 클래스를 찾아야 하는 과제에서는 Macro F1 또는 Weighted F1을 사용할 수 있다. 경보 처리 용량이 제한되면 Precision을 높이는 임계값이 필요하고, 손실 비용이 큰 경우에는 Recall을 우선하는 임계값을 택한다.

희귀 질환 검출에서는 Macro F1으로 데이터 편중에 따른 Accuracy 착시를 줄일 수 있다. 임상 민감도(Recall) 기준을 충족해야 하는 규제 환경에서는 Fβ(β>1)를 적용한다.

검색이나 콘텐츠 정책 분류에서는 유해 콘텐츠 필터링 임계값을 AB 테스트로 조정해 F1을 개선할 수 있다. 채널과 언어별 편중은 per-class F1 대시보드로 점검하며, 온라인 러닝이나 주기적 리트레이닝에서는 F1 드리프트 감지 알람을 설정한다.

양성 1%, 음성 99% 같은 불균형 상황에서는 Accuracy 99%의 착시를 제거하고 F1 0.0x 수준으로 실제 탐지력을 반영할 수 있다. 임계값 최적화로 F1 기준 10~30% 상대 개선 사례도 빈발한다. 이 과정은 도메인 편중과 운영 리스크를 인식하게 하고, 팀 간 공통 성능 기준과 의사결정의 일관성을 높인다.

예측 결과에서 F1까지 계산하는 흐름

입력은 y_true(실라벨)와 y_pred 또는 y_score(확률/점수)다. y_score가 있다면 임계값을 적용해 이진 예측을 만들고, 멀티클래스라면 argmax를 사용한다. 이후 TP/FP/FN을 계산해 Precision과 Recall을 구하고 F1을 산출한다. 멀티클래스에서는 macro, micro, weighted 평균을 적용한다.

출력으로는 단일 F1, 클래스별 F1, 평균 F1, 임계값별 F1 곡선을 확인할 수 있다.

분모가 0이 되는 zero division 상황에서는 F1=0으로 처리하거나 안전한 epsilon을 적용한다. 소수 클래스가 없는 배치에서는 macro 계산 시 해당 클래스를 제외하는 옵션을 검토한다. 확률이 보정되지 않았다면 calibration 이후 임계값 최적화를 다시 평가한다.

아니오아니오입력: y_true, y_score임계값 존재?y_pred = (y_score = t)y_pred 제공됨혼동행렬: TP/FP/FN 계산Precision = TP/(TP+FP)Recall = TP/(TP+FN)검증: 분모 0? 0처리/epsilonF1 = 2PR/(P+R)멀티클래스/멀티라벨?macro/micro/weighted평균단일 F1결과: 평균 F1 클래스별 F1

계산 예시

TP=50, FP=10, FN=30인 경우는 다음과 같다.

  • Precision = 50 / (50+10) = 0.8333
  • Recall = 50 / (50+30) = 0.625
  • F1 = 2 × 0.8333 × 0.625 / (0.8333 + 0.625) ≈ 0.7143

지표별로 보는 트레이드오프

지표 불균형 강인성 해석 용이성 TN 반영 최적화 초점 주 사용 시나리오
Accuracy 낮음 높음 전체 정답률 균형 데이터, 기초 비교
Precision 중간 중간 아니오 거짓 양성 최소화 경보 비용 큰 도메인
Recall 중간 중간 아니오 거짓 음성 최소화 누락 비용 큰 도메인
F1 Score 높음 중간 아니오 P-R 균형 불균형 데이터, 운영 최적화

임계값을 찾아 F1을 최대화하는 코드

환경/전제: Python 3.10+, scikit-learn >= 1.2, numpy, pandas

import numpy as np
from sklearn.metrics import precision_recall_curve, f1_score

# y_true: 0/1 정답, y_score: 모델 점수(확률)
def best_f1_threshold(y_true, y_score):
    precisions, recalls, thresholds = precision_recall_curve(y_true, y_score)
    # 마지막 포인트(임계값 없음)를 제외하고 F1 계산
    f1s = (2 * precisions[:-1] * recalls[:-1]) / (precisions[:-1] + recalls[:-1] + 1e-12)
    idx = np.nanargmax(f1s)
    return thresholds[idx], f1s[idx]

# 사용 예시
# y_true = np.array([...]); y_score = np.array([...])
# t, f1 = best_f1_threshold(y_true, y_score)
# y_pred = (y_score >= t).astype(int)
# print("Best t:", t, "F1:", f1, "Checked:", f1_score(y_true, y_pred))

멀티클래스에서는 같은 예측 결과에 대해 평균 방식을 달리해 비교할 수 있다.

from sklearn.metrics import f1_score

# y_true: 정답 레이블, y_pred: 예측 레이블
# average 옵션: 'macro' | 'micro' | 'weighted' | None(클래스별)
f1_macro = f1_score(y_true, y_pred, average='macro', zero_division=0)
f1_micro = f1_score(y_true, y_pred, average='micro', zero_division=0)
f1_weighted = f1_score(y_true, y_pred, average='weighted', zero_division=0)

지표와 임계값을 운영에 연결하기

극단적 불균형에서는 Macro F1을 우선하고, 클래스 중요도가 다르면 Weighted F1을 병행한다. 대규모 트래픽이나 멀티태스크에서는 Micro F1으로 전역 성능을 추적하되, 서비스별 세부 판단에는 per-class F1을 보조 지표로 둔다.

비용 구조도 임계값 선택에 반영한다. FN 비용이 높으면 Fβ(β>1)를, FP 비용이 높으면 Fβ(β<1)를 사용한다. 버전 릴리스에서는 A/B 테스트로 F1 변화를 검증하고, 데이터 쉬프트가 감지되면 임계값 재탐색을 자동화한다.

클래스 가중, 언더/오버샘플링, 합성 데이터(SMOTE)는 F1 개선과 상호 보강될 수 있다. 지역이나 성별처럼 그룹별 F1을 분해하면 공정성 이슈도 미리 탐지할 수 있다.

F1 Score불균형 데이터정밀도재현율머신러닝