ความแม่นยำ การเรียกคืน และ F1-Score ในทางปฏิบัติ
ผู้เรียนจะคำนวณความแม่นยำและการเรียกคืน เข้าใจความแลกเปลี่ยนระหว่างสองค่านี้ และเลือกตัวชี้วัดที่เหมาะสมสำหรับงานจริงที่มีสัดส่วนกลุ่มไม่สมดุล
ความแม่นยำ การเรียกคืน และ F1-Score ในทางปฏิบัติ เป็นบทเรียน Machine Learning Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Machine Learning Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน
บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ
The Precision-Recall Framework
When classes are imbalanced or when different error types have different costs, we need metrics that focus specifically on how the model handles the positive class. Precision and Recall are the two complementary metrics that fill this role.
Together, precision and recall give a complete picture of classifier behaviour on the positive class without being distorted by a large number of true negatives. This matters enormously in fraud detection, disease screening, and content moderation — all domains where the positive class is rare but critical.
Precision: Quality of Positive Predictions
Precision answers: Of all the examples the model predicted as positive, what fraction were actually positive?
Precision = TP / (TP + FP)
High precision means few false alarms. A spam filter with precision 0.99 means 99% of emails sent to the spam folder are actually spam — very few legitimate emails are misclassified. However, precision says nothing about how many real spam emails were missed. A model that flags only one email as spam and that email is spam has precision 1.0, even if it missed thousands of spam emails.
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}')Recall: Coverage of Actual Positives
Recall (also called sensitivity or true positive rate) answers: Of all the actual positive examples, what fraction did the model correctly identify?
Recall = TP / (TP + FN)
High recall means few missed positives. A cancer screening test with recall 0.95 catches 95% of patients who actually have cancer — only 5% are missed. However, recall says nothing about how many healthy patients were incorrectly flagged. High recall is essential when the cost of missing a positive (False Negative) is very high.
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}')The Precision-Recall Trade-off
Precision and recall are in tension with each other. You can always increase recall to 1.0 by predicting positive for every single example — but precision will collapse because most of those predictions are false positives. Conversely, predicting positive only when you are extremely confident (very high threshold) improves precision but misses many real positives, reducing recall.
Moving the decision threshold changes the balance. Lowering the threshold flags more examples as positive: recall goes up, precision goes down. Raising the threshold makes the model more selective: precision goes up, recall goes down. There is no threshold that maximises both simultaneously in most real problems.
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-Score: Balancing Precision and Recall
The F1-score combines precision and recall into a single number using the harmonic mean:
F1 = 2 × (Precision × Recall) / (Precision + Recall)
The harmonic mean penalises extreme imbalances: a model with precision 0.9 and recall 0.1 gets F1 = 2×0.9×0.1/1.0 = 0.18, not 0.5. This makes F1 much harder to game than a simple average. F1 = 1.0 only when both precision and recall are 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 Score: Weighting Precision and Recall
The F1-score treats precision and recall as equally important. The Fβ score lets you weight recall β times more than precision:
Fβ = (1 + β²) × Precision × Recall / (β² × Precision + Recall)
- β = 1: standard F1 (equal weight)
- β = 2 (F2): recall is twice as important — use for cancer screening where missing a case is critical
- β = 0.5 (F0.5): precision is twice as important — use for spam filters where false alarms are costly
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')Precision-Recall Curves
Instead of evaluating at one threshold, a precision-recall curve plots precision vs recall across all possible thresholds. The shape of the curve tells you the best achievable trade-off for your model.
A model with high area under the precision-recall curve (PR-AUC) is better at finding positives without generating too many false alarms. PR-AUC is preferred over ROC-AUC when the positive class is rare, because it focuses on performance on the minority class rather than being influenced by the large pool of true negatives.
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()Macro, Micro, and Weighted Averages
For multi-class classification, scikit-learn reports several types of averages for precision, recall, and F1:
- Macro average: compute metric per class, then take unweighted mean. Treats all classes equally regardless of size.
- Weighted average: compute metric per class, then take mean weighted by the number of examples per class. Reflects overall dataset performance.
- Micro average: aggregate TP/FP/FN across all classes, then compute the metric. For accuracy this equals overall accuracy.
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']))Choosing the Right Metric for Your Problem
A decision framework for metric selection:
- Balanced classes, equal error costs → Accuracy
- Imbalanced classes, cost of FP high → Precision (e.g., spam filter — don't trash good emails)
- Imbalanced classes, cost of FN high → Recall (e.g., disease screening — don't miss sick patients)
- Both FP and FN costly, need single metric → F1
- FN much more costly than FP → F2 (cancer detection, fraud where you can investigate)
- Need to evaluate across all thresholds → PR-AUC or ROC-AUC
Specificity and the Confusion Matrix Complete
Two additional metrics complete the picture of binary classifier performance:
- Specificity (True Negative Rate) = TN / (TN + FP): of all actual negatives, what fraction did the model correctly identify? High specificity means few false alarms. Used together with sensitivity (recall) in medical testing.
- Fall-out (False Positive Rate) = FP / (FP + TN): the complement of specificity. The x-axis of the ROC curve that you will study in the evaluation metrics lesson.
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')Classification Report with Custom Thresholds
The default threshold of 0.5 is not always optimal. A workflow for finding the best threshold: compute precision, recall, and F1 at many thresholds, then pick the threshold that maximises the metric relevant to your problem.
For a fraud detection scenario, you might maximise F2 to prioritise recall. For a content moderation system, you might maximise precision to avoid incorrectly removing legitimate content. The precision_recall_curve function gives you all the data you need for this analysis.
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}')Quick Check
Test your understanding of Machine Learning with Python concepts from this lesson.
Lesson Recap
In this lesson you learned: precision measures quality of positive predictions (TP/(TP+FP)), recall measures coverage of actual positives (TP/(TP+FN)), and the F1-score harmonic mean balances both — while Fβ lets you weight recall or precision more heavily based on your application's error cost structure. Next up we tackle the fundamental question of model evaluation: why you cannot evaluate a model on the data it was trained on, and how to properly estimate generalisation performance with held-out test sets.
คำถามที่พบบ่อย
บทเรียน “ความแม่นยำ การเรียกคืน และ F1-Score ในทางปฏิบัติ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ความแม่นยำ การเรียกคืน และ F1-Score ในทางปฏิบัติ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Machine Learning Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ความแม่นยำ การเรียกคืน และ F1-Score ในทางปฏิบัติ”
ผู้เรียนจะคำนวณความแม่นยำและการเรียกคืน เข้าใจความแลกเปลี่ยนระหว่างสองค่านี้ และเลือกตัวชี้วัดที่เหมาะสมสำหรับงานจริงที่มีสัดส่วนกลุ่มไม่สมดุล คุณปฏิบัติ Machine Learning Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Machine Learning Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Machine Learning Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ความแม่นยำ การเรียกคืน และ F1-Score ในทางปฏิบัติ” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Machine Learning Academy นี้ได้ไหม
ได้ บทเรียน Machine Learning Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- จากการถดถอยสู่การจำแนก: การตัดสินใจด้วยค่าเกณฑ์
- การถดถอยลอจิสติกและฟังก์ชันซิกมอยด์
- อธิบายเมทริกซ์ความสับสน
- ความแม่นยำ การเรียกคืน และ F1-Score ในทางปฏิบัติ