LLM 엔지니어링1장 · 머신러닝 프로세스와 기본 개념11 / 23← 이전목차다음 →MetaContents

1장. 머신러닝 프로세스와 기본 개념

정확도·정밀도·재현율·F1

호수에서 그물로 물고기를 잡는다고 해 봅시다. 그물에는 물고기도 걸리고 나뭇가지도 걸립니다. "건진 것 가운데 물고기가 얼마나 되나"와 "호수의 물고기 가운데 얼마나 건졌나"는 서로 다른 질문입니다. 앞의 것이 정밀도, 뒤의 것이 재현율입니다. 그물을 넓게 던지면 물고기를 많이 건지지만 나뭇가지도 많이 걸립니다.

정확도, 정밀도, 재현율, F1 점수의 뜻과 쓰는 때를 네 장의 카드로 나란히 놓은 그림

카드는 지표 하나에 하나씩입니다. 윗줄이 뜻, 아랫줄이 그 지표를 앞세울 때입니다. 여기서 물고기가 실제 지연 주문이고, 그물에 건진 것이 "지연"이라고 예측한 주문입니다. 비유와 다른 점은, 호수의 물고기 수는 모르지만 시험용 데이터의 실제 지연 수는 안다는 것입니다. 그래서 재현율을 계산할 수 있습니다.

지표 네 가지

지표계산(혼동행렬 칸으로)뜻이 지표를 볼 때
정확도(TP + TN) ÷ 전체전체에서 맞힌 비율두 답의 수가 비슷할 때
정밀도TP ÷ (TP + FP)"늦는다"고 한 말이 맞을 확률(얼마나 믿을 만한가)헛경보의 비용이 클 때
재현율TP ÷ (TP + FN)실제로 늦은 주문을 빠짐없이 찾아낸 비율(얼마나 놓치지 않았나)놓침의 비용이 클 때
F1 점수정밀도와 재현율의 조화평균둘을 함께 본 점수. 둘 가운데 낮은 쪽에 끌려간다하나만 보기 어려울 때
정확도, 정밀도, 재현율은 혼동행렬에서 분자와 분모에 쓰는 칸을 색으로 칠하고, F1 은 정밀도와 재현율 막대로 보이며, 혼동행렬 절의 예 10건으로 계산한 값을 적은 그림

표의 계산식을 혼동행렬 칸으로 그린 그림입니다. 숫자는 "혼동행렬" 절의 예(TP 2, FN 2, FP 1, TN 5)입니다. 카드마다 진하게 칠한 칸이 분자(나누어지는 수), 옅게 칠한 칸이 분모에만 더하는 칸이고, 회색 칸은 그 지표에 쓰지 않습니다. 정확도(청록)는 네 칸을 모두 분모로 써서 맞힌 대각선 두 칸(TP, TN)의 비율을 봅니다. 정밀도(마젠타)는 "예측 지연" 세로줄만, 재현율(다홍)은 "실제 지연" 가로줄만 씁니다. 두 지표가 같은 TP 를 분자로 쓰지만, 정밀도는 모델이 "늦는다"고 한 주문 가운데에서, 재현율은 실제로 늦은 주문 가운데에서 센다는 것이 그림으로 보입니다. F1 점수(빨강)는 칸이 아니라 정밀도와 재현율로 계산하므로 막대로 보였습니다. F1 막대(0.571)가 두 막대의 가운데(0.583)보다 조금 짧아 낮은 재현율 쪽에 끌려간 것을 볼 수 있습니다.

재현율을 쉽게: "늦는 주문을 몇 개나 미리 찾았나"

재현율은 숨바꼭질의 술래에 빗대면 쉽습니다. 친구 4명이 숨었는데 술래가 2명을 찾았다면, 찾아낸 비율은 4명 가운데 2명, 곧 0.5 입니다. 엉뚱한 곳을 몇 번 뒤졌는지는 따지지 않고, 숨은 친구를 빠짐없이 찾았는지만 봅니다. 여기서 숨은 친구가 실제로 늦은 주문이고, 찾아낸 친구가 모델이 "늦는다"고 미리 알린 주문입니다.

묻는 것재현율정밀도
한 문장으로늦은 주문을 빠짐없이 찾았나"늦는다"고 한 말을 믿을 수 있나
나누는 수(분모)실제로 늦은 주문 전체모델이 "늦는다"고 한 주문 전체
떨어지는 까닭늦는 주문을 놓쳤다(놓침)제때 올 주문을 늦는다고 했다(헛경보)
높이려면"늦는다"고 더 자주 말한다확실할 때만 "늦는다"고 말한다

"혼동행렬" 절의 예에서는 실제로 늦은 주문이 4건이고, 모델이 그 가운데 2건을 "늦는다"고 미리 알렸습니다. 재현율은 2 ÷ 4 = 0.5, 늦는 주문의 절반을 놓쳤다는 뜻입니다. 고객에게 지연 안내 문자를 미리 보내는 일이라면, 놓친 2건의 고객은 아무 안내 없이 늦은 물건을 받습니다. 재현율은 이런 놓침이 얼마나 적은지를 보는 점수입니다.

F1 의 조화평균은 무엇인가

자동차로 60km 를 갈 때 시속 60km, 돌아올 때 시속 20km 로 달렸다고 해 봅시다. 평균 속도는 (60 + 20) ÷ 2 = 40 이 아닙니다. 갈 때 1시간, 올 때 3시간이 걸려 120km 를 4시간에 달렸으니 시속 30km 입니다. 느렸던 쪽에서 시간을 오래 썼기 때문에 평균이 느린 쪽으로 끌려갑니다. 이렇게 낮은 쪽에 더 끌려가는 평균이 조화평균입니다. 여기서 두 속도가 정밀도와 재현율이고, 왕복의 평균 속도가 F1 점수입니다.

F1 점수는 정밀도와 재현율의 조화평균이고, 식으로는 2 × 정밀도 × 재현율 ÷ (정밀도 + 재현율)입니다. 그냥 평균(산술평균)을 쓰지 않는 까닭은, 한쪽만 아주 높고 다른 쪽이 낮은 모델을 좋게 보지 않으려는 것입니다.

정밀도재현율산술평균F1(조화평균)읽는 법
0.9000.9000.9000.900둘이 같으면 두 평균도 같다
0.6670.5000.5830.571아래 코드의 예. 조금 낮은 재현율 쪽으로 끌려간다
1.0000.1000.5500.182확실한 한 건만 "늦는다"고 한 모델. 늦는 주문의 90% 를 놓쳤는데, 산술평균은 0.55 로 좋아 보인다

마지막 줄처럼 "늦는다"고 거의 말하지 않는 모델은 정밀도가 1.000 이어도 쓸모가 없습니다. 산술평균은 0.550 으로 이 문제를 가리지만, F1 은 0.182 로 낮게 나와 문제를 드러냅니다.

Python
# 정밀도와 재현율로 산술평균과 F1(조화평균)을 견준다
for precision, recall in [(0.9, 0.9), (2 / 3, 0.5), (1.0, 0.1)]:
    mean = (precision + recall) / 2
    f1 = 2 * precision * recall / (precision + recall)   # 조화평균
    # 결과: 둘이 벌어질수록 F1 이 산술평균보다 낮아진다
    print(f"정밀도 {precision:.3f} · 재현율 {recall:.3f} → 산술평균 {mean:.3f} · F1 {f1:.3f}")

기준선부터 구한다

지연이 전체의 20% 라면 "늘 정시"라고만 답해도 정확도는 80% 입니다. 이 단순한 답의 점수가 기준선입니다. 모델의 정확도가 81% 라면 거의 아무것도 배우지 못한 셈입니다. 정답이 한쪽으로 쏠린 문제에서 정확도보다 재현율과 정밀도를 봐야 하는 까닭입니다. 실습 5에서 실제로 이 일이 일어납니다.

코드로 계산하기

"혼동행렬" 절의 예를 그대로 씁니다.

Python
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

y_true = [1, 1, 1, 1, 0, 0, 0, 0, 0, 0]   # 실제: 지연 4건
y_pred = [1, 1, 0, 0, 1, 0, 0, 0, 0, 0]   # 예측: 지연이라고 한 것 3건

# 네 함수 모두 (실제, 예측) 순서로 넣는다. 1(지연)을 기준으로 계산한다
print("정확도", accuracy_score(y_true, y_pred))
print("정밀도", round(precision_score(y_true, y_pred), 3))
print("재현율", recall_score(y_true, y_pred))
print("F1", round(f1_score(y_true, y_pred), 3))

지연 4건 가운데 2건을 잡았으므로 재현율은 0.5 입니다. 지연이라고 한 3건 가운데 2건이 맞았으므로 정밀도는 0.667 입니다. 정확도는 10건 가운데 7건을 맞혀 0.7, F1 은 0.571 입니다.

코드에 나오는 함수

코드쉬운 뜻
f"{precision:.3f}"숫자를 소수 셋째 자리까지 적은 글자로 바꾼다. f 는 소수점 아래 자리 수를 정해 적는 꼴(fixed-point, 고정 소수점)이라는 표시다
accuracy_score(y_true, y_pred)accuracy(정확도). 전체 가운데 맞힌 비율을 돌려준다
precision_score(y_true, y_pred)precision(정밀함). "지연"이라고 한 것 가운데 실제 지연의 비율이다
recall_score(y_true, y_pred)recall(다시 불러내기, 떠올리기). 실제 지연 가운데 찾아낸 비율이다
f1_score(y_true, y_pred)정밀도와 재현율의 조화평균이다. F 점수(F-score) 가운데 두 지표에 같은 무게(1)를 주는 것이라 F1 이라고 부른다

이 코드가 뜻하는 것

그물로 물고기를 잡은 뒤 성적표를 쓰는 일입니다. 같은 그물질 결과(혼동행렬 절의 10건)를 놓고 네 가지 물음에 답합니다. 여기서 물고기가 실제 지연, 건져 올린 것이 "지연"이라는 예측입니다.

줄하는 일쉽게 말하면
첫 코드의 for precision, recall in [...]세 쌍으로 산술평균과 F1 을 계산한다갈 때와 올 때 속도로 평균 속도를 구한다
accuracy_score(y_true, y_pred)10건 가운데 맞힌 비율물고기와 나뭇가지를 바르게 가른 비율
precision_score(y_true, y_pred)"지연" 3건 가운데 맞은 비율건진 것 가운데 물고기의 비율
recall_score(y_true, y_pred)실제 지연 4건 가운데 찾은 비율호수의 물고기 가운데 건진 비율
f1_score(y_true, y_pred)정밀도와 재현율을 함께 본 점수두 성적을 묶은 한 줄 평

정확도 0.7 은 그럴듯해 보여도, 재현율 0.5 는 늦는 주문의 절반을 놓쳤다는 뜻입니다. 한 숫자만 보지 말고 네 숫자를 함께 읽어야 합니다.

기준선을 코드로 구해 보기

"늘 정시"라고만 답하는 기준선이 같은 10건에서 몇 점을 받는지 계산합니다.

Python
from sklearn.metrics import accuracy_score, precision_score, recall_score

y_true = [1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
y_base = [0] * 10   # 기준선: 늘 "정시"라고만 답한다

print("정확도", accuracy_score(y_true, y_base))
print("재현율", recall_score(y_true, y_base))
# zero_division=0: "지연"이라고 한 주문이 하나도 없어 0 으로 나누게 될 때 0 으로 적는다
print("정밀도", precision_score(y_true, y_base, zero_division=0))
출력
정확도 0.6
재현율 0.0
정밀도 0.0
결과읽는 법
정확도 0.6아무것도 배우지 않고 정시 6건을 맞혔다. 이 10건에서 모델의 정확도는 적어도 0.6 을 넘어야 한다
재현율 0.0늦는 주문을 하나도 찾지 못했다
정밀도 0.0"지연"이라고 한 적이 없어서 원래는 계산할 수 없다. zero_division=0 으로 0 이라고 적게 했다

앞의 모델은 정확도 0.7 로 기준선 0.6 보다 0.1 높을 뿐이지만, 재현율은 0 에서 0.5 로 올랐습니다. 정답이 한쪽으로 쏠릴수록 이 차이가 커집니다.

주의할 점

  • 함수에 넣는 순서는 언제나 (실제, 예측)입니다. 바꿔 넣으면 정밀도와 재현율이 뒤바뀝니다.
  • 정밀도와 재현율은 기본으로 1(지연)을 기준으로 셉니다. 0 쪽을 보고 싶으면 pos_label=0 을 줍니다. 프로젝트에서 부정 리뷰를 볼 때 씁니다.
← 이전 절1장 · 혼동행렬다음 절 →1장 · 기준값 바꾸기