Model Evaluation: Accuracy, Precision, Recall, F1
Objectives
Section titled “Objectives”After this lesson, you will be able to:
- Recognize why accuracy is deceptive on imbalanced datasets, and always compare it against a majority-class baseline.
- Read a confusion matrix and compute precision, recall, and F1 from the four quadrants (TP, FP, FN, TN). Derive why F1 relies on the harmonic mean.
- Understand the precision–recall trade-off when tuning decision thresholds, identifying when to prioritize precision versus recall, and selecting thresholds on a validation set.
- Interpret precision–recall curves, ROC curves with AUC, and evaluate
macro avgversusweighted avgin scikit-learn’sclassification_report.
Prerequisites
Section titled “Prerequisites”- Logistic Regression, in Machine Learning (Learned)
Intuition
Section titled “Intuition”A clinic evaluates a diagnostic screening model on 20 patients with confirmed laboratory test results. Exactly 6 of them have the disease. For each patient, the model outputs an estimated probability of having the disease. The table below lists patients ranked in descending order of (synthetic data generated for this lesson).
| Patient | Probability | True Label |
|---|---|---|
| 1 | 0.93 | 1 |
| 2 | 0.86 | 1 |
| 3 | 0.78 | 0 |
| 4 | 0.71 | 1 |
| 5 | 0.63 | 0 |
| 6 | 0.58 | 1 |
| 7 | 0.54 | 0 |
| 8 | 0.46 | 1 |
| 9 | 0.42 | 0 |
| 10 | 0.36 | 0 |
| 11 | 0.31 | 1 |
| 12 | 0.27 | 0 |
| 13 | 0.22 | 0 |
| 14 | 0.18 | 0 |
| 15 | 0.14 | 0 |
| 16 | 0.12 | 0 |
| 17 | 0.09 | 0 |
| 18 | 0.07 | 0 |
| 19 | 0.04 | 0 |
| 20 | 0.02 | 0 |
A Trivial Model Can Still Score 70%
Section titled “A Trivial Model Can Still Score 70%”The most obvious evaluation approach is counting correct predictions. By standard convention, anyone with is predicted as “diseased”. Patients 1 through 7 are predicted positive; the remaining 13 are predicted negative. Comparing with column , the model is correct for 15 out of 20 patients, yielding 75% accuracy.
That seems reasonable. Now consider a “dummy” model that learns nothing and predicts healthy every time. It correctly identifies all 14 healthy individuals, securing accuracy. The trained model is merely 5 percentage points better.
Worse yet, the trivial “always healthy” model detects not a single sick patient. It is entirely useless for medical screening, yet boasts a 70% score. If the disease were rarer—say, 1 in 100 people—a dummy model would trivially reach 99% accuracy.
Not All Errors Are Created Equal
Section titled “Not All Errors Are Created Equal”A single 75% accuracy figure conceals a critical nuance: what types of mistakes the model makes. The 5 misclassified patients fall into two distinct categories:
- Patients 3, 5, and 7 are healthy but flagged as sick. They undergo unnecessary confirmatory testing, incurring financial cost and anxiety.
- Patients 8 and 11 have the disease but are told they are healthy. They return home, missing timely intervention.
In medical screening, the second failure mode is vastly more dangerous. Accuracy treats both errors as completely equal.
Furthermore, the 0.5 threshold is an arbitrary design choice. Lowering it to 0.3 catches patients 8 and 11, but also misdiagnoses patients 9 and 10. Each threshold produces a different trade-off between error types.
The core problem of this lesson is: how to evaluate classification quality so that specific error types are exposed—especially under class imbalance—and how to select thresholds aligned with real-world operating costs.
Theory
Section titled “Theory”From Probabilities to Labels: Decision Thresholds
Section titled “From Probabilities to Labels: Decision Thresholds”Let be the model’s estimated probability that sample belongs to the positive class. To assign a predicted label , we compare against a decision threshold :
Scikit-learn’s predict method applies by default (strictly predicting positive when , differing only at exact ties), but nothing obligates using 0.5. The model learns probabilities ; choosing is your decision based on asymmetric error costs. All metrics discussed below (except AUC) are calculated after choosing ; shifting shifts the metrics.
Confusion Matrix
Section titled “Confusion Matrix”Comparing predicted label with true label , every sample falls into one of four distinct categories:
| True Label | Predicted Positive () | Predicted Negative () |
|---|---|---|
| Positive () | TP: True Positive | FN: False Negative |
| Negative () | FP: False Positive | TN: True Negative |
- TP (True Positive): Has disease, predicted positive.
- FN (False Negative): Has disease, predicted negative. A missed detection (Type II error).
- FP (False Positive): Healthy, predicted positive. A false alarm (Type I error).
- TN (True Negative): Healthy, predicted negative.
The second letter (P or N) represents the model’s prediction. The first letter (T or F) indicates whether that prediction is correct. This layout is the confusion matrix.
For our 20 patients with : TP comprises patients 1, 2, 4, 6; FP includes 3, 5, 7; FN contains 8 and 11; the remaining eleven individuals are TN.
| True Label | Predicted Positive | Predicted Negative |
|---|---|---|
| Positive (6 patients) | TP = 4 | FN = 2 |
| Negative (14 patients) | FP = 3 | TN = 11 |
Row sums represent actual class sizes in the dataset and remain constant regardless of threshold. Column sums represent the number of predicted positives and negatives, varying with .
Accuracy
Section titled “Accuracy”Accuracy is the proportion of correctly classified instances across all samples—the sum of the diagonal divided by the total:
The “always negative” model has , giving accuracy . The vast majority of points contributing to accuracy stem from the TN quadrant—the dominant class. The more imbalanced the classes, the more TN overwhelms the score, rendering accuracy uninformative regarding the minority positive class.
Precision and Recall
Section titled “Precision and Recall”To evaluate the positive class specifically, we use two complementary metrics:
Precision: Among all samples predicted positive, what proportion is truly positive? We divide TP by the entire “predicted positive” column:
Recall (also known as sensitivity or true positive rate): Among all samples that are truly positive, what proportion did the model catch? We divide TP by the entire “actual positive” row:
Both formulas share the numerator TP, differing only in the denominator. Precision is degraded by false alarms (FP). Recall is degraded by missed detections (FN).
For the negative class, an analogous metric to recall is specificity (true negative rate): the fraction of actual negatives correctly classified as negative:
In medicine, diagnostic tests are commonly characterized by sensitivity and specificity. In machine learning, the precision–recall pair is more prevalent.
For the trivial “always negative” baseline: , immediately unmasking what 70% accuracy disguised. Its precision evaluates to : having zero positive predictions, it is mathematically undefined. Scikit-learn issues a warning and returns 0 by default (customizable via the zero_division parameter).
F1: Combining Precision and Recall into a Single Metric
Section titled “F1: Combining Precision and Recall into a Single Metric”Comparing models with a single number is often convenient. The arithmetic mean is tempting, but flawed. Consider threshold : only patient 1 is predicted positive, yielding and . Their arithmetic mean is —higher than at , despite missing 5 out of 6 sick individuals.
The F1 score resolves this by computing the harmonic mean: averaging the reciprocals, then inverting:
The right-hand side follows by finding a common denominator and taking the reciprocal.
Why does the harmonic mean prevent distortion? Small numbers have large reciprocals. When , dominates , driving the average reciprocal high and compressing low. At :
F1 is strongly pulled toward the smaller of the two values. To achieve a high F1 score, both precision and recall must be high.
Expressing and directly in terms of TP, FP, and FN produces an alternative representation:
Inverting yields:
At : . Notice that the TN term is absent: a flood of true negatives cannot inflate F1 the way it inflates accuracy. Additionally, this form is computable even when positive predictions are zero: when , , whereas precision would be .
F-beta. When one error type carries higher stakes, the generalized score balances them:
Setting recovers . Setting weights recall more heavily (e.g., for medical screening), whereas favors precision (e.g., ). In scikit-learn, this is accessible via fbeta_score.
The Precision–Recall Trade-off Across Thresholds
Section titled “The Precision–Recall Trade-off Across Thresholds”Varying across our 20 patients demonstrates this trade-off. The second code cell prints full sweeps from 0.1 to 0.9; representative values are summarized below:
| Threshold | TP | FP | FN | TN | Accuracy | Precision | Recall | F1 |
|---|---|---|---|---|---|---|---|---|
| 0.30 | 6 | 5 | 0 | 9 | 0.750 | 0.545 | 1.000 | 0.706 |
| 0.50 | 4 | 3 | 2 | 11 | 0.750 | 0.571 | 0.667 | 0.615 |
| 0.70 | 3 | 1 | 3 | 13 | 0.800 | 0.750 | 0.500 | 0.600 |
| 0.80 | 2 | 0 | 4 | 14 | 0.800 | 1.000 | 0.333 | 0.500 |
| 0.95 | 0 | 0 | 6 | 14 | 0.700 | undefined | 0.000 | 0.000 |
Raising causes fewer samples to be flagged as positive:
- Recall never increases. Samples can only drop out of the positive set, so TP is non-increasing while the denominator remains fixed at 6.
- Precision usually rises, but non-monotonically. While FP decreases, TP can also fall. Moving from to , the sample eliminated is patient 11 (a true positive), causing precision to drop from to .
- Accuracy can rise even as model clinical utility plummets. At , accuracy climbs to (higher than at ), yet recall drops to , abandoning 4 out of 6 sick patients.
There is no universally optimal threshold. The question is: which mistake is more costly?
- Prioritize recall when misses are expensive. In clinical screening, a false alarm merely requires a follow-up test, whereas a missed diagnosis may prove fatal. Lower the threshold. Fraud detection often adopts the same stance.
- Prioritize precision when false alarms are costly. In spam filtering, an occasional junk email in the inbox is minor, but diverting a critical job offer to spam can be disastrous. Raise the threshold.
Selecting tunes a hyperparameter. Therefore, optimize it on the validation set (or via cross-validation as taught in Overfitting and Underfitting), and evaluate on the test set once with the finalized threshold. Searching for the highest test F1 across thresholds commits the pitfall of “selecting models using test data” highlighted in Introduction to Machine Learning. Scikit-learn provides TunedThresholdClassifierCV to automate this procedure cleanly.
Precision–Recall and ROC Curves
Section titled “Precision–Recall and ROC Curves”Rather than inspecting discrete thresholds, sweeping across all possible thresholds traces continuous evaluation curves.
The precision–recall curve plots recall on the horizontal axis and precision on the vertical axis. Every point corresponds to a threshold. A high-performing classifier hugs the upper-right corner (high recall with sustained high precision). A random guessing baseline forms a flat horizontal line at the dataset’s positive prevalence rate ().
The ROC curve (Receiver Operating Characteristic) plots the false positive rate (FPR) on the x-axis:
against recall (true positive rate) on the y-axis. Lowering from 1 to 0 traces a curve from (predicting nobody positive) to (predicting everyone positive). Random guessing follows the diagonal.
AUC (Area Under the Curve) measures the area under the ROC curve, ranging from 0 to 1. It carries an intuitive probabilistic interpretation: given a randomly chosen positive sample and negative sample, AUC is the probability that the model ranks the positive sample higher than the negative one. Among our 20 patients, there are positive-negative pairs. Inspecting the table: patient 4 is ranked below 1 healthy patient (patient 3), patient 6 below 2, patient 8 below 3, patient 11 below 5. In total, 11 pairs are inverted:
AUC depends solely on prediction rank ordering, completely independent of any chosen threshold. It is ideal for comparing model ranking capabilities prior to selecting an operating threshold. When the positive class is heavily outnumbered, the vast number of TNs keeps FPR perpetually small, making ROC curves appear deceptively optimistic. Under severe class imbalance, the precision–recall curve provides a much more faithful reflection of minority-class performance.
Multi-class: Macro, Micro, and Weighted Averages
Section titled “Multi-class: Macro, Micro, and Weighted Averages”For classes (e.g., digit recognition from 0 to 9, covered in Softmax Regression), one calculates precision, recall, and F1 for each individual class by treating it as positive and all others as negative. These scores are then aggregated using one of three strategies:
- Macro average: The unweighted arithmetic mean across all classes, weighting each class equally. Poor performance on a rare class significantly penalizes the macro score.
- Weighted average: The mean weighted by the true support (sample count) of each class. Dominant classes control the score.
- Micro average: Aggregates total TP, FP, and FN across all classes before computing a global metric. When every sample has exactly one ground truth label, micro precision, recall, and F1 all mathematically equal overall accuracy.
To diagnose whether a model neglects minority classes, always check macro avg. The third code example illustrates how widely these aggregations can diverge.
Limitations
Section titled “Limitations”- Small sample sizes cause high variance in metrics. With only 6 positive patients, catching or missing one individual shifts recall by . Treat figures on 20 patients as educational illustrations.
- Metrics do not incorporate dollar costs directly. F1 treats FP and FN symmetrically; adjusts their weighting heuristically. When real business costs are known, select the threshold that minimizes expected financial loss.
- Threshold-dependent metrics do not verify probability calibration. A well-calibrated model ensures that among cases assigned , approximately 90% are truly positive. Calibration is an orthogonal property not captured by thresholded counts.
- Measuring imbalance is not equivalent to remedying it. Techniques for handling class imbalance (resampling, class-weighted loss) are detailed in Data Preprocessing.
Visualization
Section titled “Visualization”The interactive tool below displays all 20 patients along a probability axis from 0 to 1, colored by their true label (diseased or healthy). The slider adjusts threshold from 0 to 1 in steps of 0.05. A vertical guideline marks the current threshold; all points to the right (including those landing directly on the boundary) are predicted positive. Alongside, the confusion matrix and the four metrics (accuracy, precision, recall, F1) update dynamically as you drag. Try the following:
- Initial state at : . Accuracy is 0.750, precision 0.571, recall 0.667, F1 0.615. Two positive dots lie left of the line: these represent missed cases.
- Drag down to : all 6 diseased patients fall to the right, raising recall to 1.000. In return, FP increases to 5, lowering precision to 0.545, while F1 climbs to 0.706.
- Drag up to : false alarms vanish (), driving precision to 1.000. However, recall plummets to 0.333, yet accuracy increases to 0.800: accuracy rewards missing sick patients because healthy patients dominate the population.
- Drag up to : nobody is predicted positive. Precision displays ”—” (), recall and F1 hit 0, and accuracy registers 0.700—matching the dummy baseline.
- Ill (y = 1)
- Not ill (y = 0)
- Threshold line t
| True label | Predicted positive | Predicted negative |
|---|---|---|
| Positive (6) | TP = 4 | FN = 2 |
| Negative (14) | FP = 3 | TN = 11 |
No positive predictions: precision is 0/0, undefined.
20 made-up patients, 6 ill and 14 not ill, placed by the probability of being ill that the model predicts. Most ill patients get a high probability, but the two groups overlap between about 0.3 and 0.8.
Code Examples
Section titled “Code Examples”The three cells below run independently, each handling its own imports and synthetic datasets. The first two replicate the 20-patient dataset. Loading scikit-learn in the browser adds a brief delay on initial execution.
The first cell sets threshold , tallies the four confusion matrix cells with NumPy, computes metrics manually from definitions, and validates them against sklearn.metrics. The syntax (p >= t).astype(int) converts booleans to binary indicator arrays. The expression (y_pred == 1) & (y_true == 1) masks matching conditions, and np.sum counts them.
Confusion matrix at threshold 0.5
import numpy as npfrom sklearn.metrics import (accuracy_score, confusion_matrix, f1_score, precision_score, recall_score)
# 20 patients (made-up illustration data), sorted by probability, high first.# y_true: true label (1 = has the disease). p: predicted disease probability.y_true = np.array([1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])p = np.array([0.93, 0.86, 0.78, 0.71, 0.63, 0.58, 0.54, 0.46, 0.42, 0.36, 0.31, 0.27, 0.22, 0.18, 0.14, 0.12, 0.09, 0.07, 0.04, 0.02])
t = 0.5 # decision thresholdy_pred = (p >= t).astype(int) # predict positive when p >= t
# Count the four cells of the confusion matrix.tp = np.sum((y_pred == 1) & (y_true == 1))fp = np.sum((y_pred == 1) & (y_true == 0))fn = np.sum((y_pred == 0) & (y_true == 1))tn = np.sum((y_pred == 0) & (y_true == 0))print(f"TP = {tp}, FP = {fp}, FN = {fn}, TN = {tn}")
accuracy = (tp + tn) / len(y_true)precision = tp / (tp + fp)recall = tp / (tp + fn)f1 = 2 * precision * recall / (precision + recall) # harmonic meanprint(f"by hand: acc = {accuracy:.3f}, P = {precision:.3f}, " f"R = {recall:.3f}, F1 = {f1:.3f}")
# Check against scikit-learn.print(confusion_matrix(y_true, y_pred)) # rows: true label 0, 1print(f"sklearn: acc = {accuracy_score(y_true, y_pred):.3f}, " f"P = {precision_score(y_true, y_pred):.3f}, " f"R = {recall_score(y_true, y_pred):.3f}, " f"F1 = {f1_score(y_true, y_pred):.3f}")
# The "always predict healthy" model: accuracy is still high.print(f"always 0: acc = {np.mean(y_true == 0):.3f}")The first run downloads Python, about 10 MB.
The output confirms the theory section: . Hand calculations and scikit-learn outputs match identically: accuracy 0.750, precision 0.571, recall 0.667, F1 0.615. The final row reflects the “always healthy” dummy baseline scoring 0.700 accuracy.
Note scikit-learn’s quadrant orientation in confusion_matrix: rows represent true labels, columns represent predictions, and class 0 appears first. Thus, top-left 11 is TN, and bottom-right 4 is TP.
The second cell sweeps thresholds from 0.1 through 0.9, prints precision, recall, and F1 at each point, and plots both performance curves. Built-in utilities precision_recall_curve and roc_curve automatically evaluate all relevant candidate thresholds from continuous probabilities .
Threshold sweeping, PR curve, and ROC curve
import matplotlib.pyplot as pltimport numpy as npfrom sklearn.metrics import (f1_score, precision_recall_curve, precision_score, recall_score, roc_auc_score, roc_curve)
# 20 patients (made-up illustration data), sorted by probability, high first.y_true = np.array([1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])p = np.array([0.93, 0.86, 0.78, 0.71, 0.63, 0.58, 0.54, 0.46, 0.42, 0.36, 0.31, 0.27, 0.22, 0.18, 0.14, 0.12, 0.09, 0.07, 0.04, 0.02])
# Sweep the threshold from 0.1 to 0.9 in steps of 0.1.print(" t P R F1")for t in np.round(np.arange(0.1, 0.95, 0.1), 2): y_pred = (p >= t).astype(int) P = precision_score(y_true, y_pred, zero_division=0) # report 0 for 0/0 R = recall_score(y_true, y_pred) F = f1_score(y_true, y_pred) print(f"{t:.2f} {P:.3f} {R:.3f} {F:.3f}")
# Two curves: each point on a curve is one threshold.prec, rec, _ = precision_recall_curve(y_true, p)fpr, tpr, _ = roc_curve(y_true, p)auc = roc_auc_score(y_true, p)print(f"ROC AUC = {auc:.3f}")
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4))ax1.plot(rec, prec, marker="o")ax1.axhline(y_true.mean(), ls="--", c="gray") # random-guess levelax1.set(xlabel="recall", ylabel="precision", title="Precision-recall")ax2.plot(fpr, tpr, marker="o", label=f"model (AUC = {auc:.2f})")ax2.plot([0, 1], [0, 1], ls="--", c="gray", label="random")ax2.set(xlabel="false positive rate", ylabel="recall (TPR)", title="ROC")ax2.legend()plt.tight_layout()plt.show()The first run downloads Python, about 10 MB.
Reading across the threshold table columns:
- Recall holds steady at 1.000 until threshold 0.3, then declines to 0.167 at 0.9. It never increases as thresholds rise.
- Precision rises from 0.375 toward 1.000 non-monotonically, exhibiting plateaus (0.545, 0.556, 0.571 across thresholds 0.3, 0.4, 0.5).
- F1 reaches its peak at threshold 0.3 with approximately 0.706, confirming that on this dataset, operating below the 0.5 default is beneficial.
The reported ROC AUC = 0.869 confirms our manual ranking derivation (73 out of 84 pairs). On the left plot, the sawtooth pattern in the precision–recall curve reflects discrete data points: crossing a healthy patient lowers precision, while crossing a sick patient advances recall rightward and lifts precision. On large datasets, these steps diminish into smooth curves.
The third cell tests realistic class imbalance: 2,000 synthetic samples generated via make_classification, with only 5% positive instances. Data is split into training, validation, and test subsets (60%, 20%, 20%) with stratified class proportions. The code compares three approaches: a DummyClassifier predicting majority class, logistic regression under default threshold 0.5, and logistic regression with its threshold tuned on the validation set.
Imbalanced classification and threshold tuning
import numpy as npfrom sklearn.datasets import make_classificationfrom sklearn.dummy import DummyClassifierfrom sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import classification_report, f1_score, recall_scorefrom sklearn.model_selection import train_test_split
# 2000 samples, only about 5% in the positive class (class 1).X, y = make_classification(n_samples=2000, n_features=10, n_informative=4, weights=[0.95, 0.05], class_sep=2.0, random_state=0)# Three sets: train 60%, validation 20%, test 20%, same class ratio.X_tmp, X_test, y_tmp, y_test = train_test_split( X, y, test_size=0.2, stratify=y, random_state=0)X_tr, X_val, y_tr, y_val = train_test_split( X_tmp, y_tmp, test_size=0.25, stratify=y_tmp, random_state=0)
# A "dumb" model: always predict the majority class (class 0).dummy = DummyClassifier(strategy="most_frequent").fit(X_tr, y_tr)d_pred = dummy.predict(X_test)print(f"dummy: acc = {np.mean(d_pred == y_test):.3f}, " f"R = {recall_score(y_test, d_pred):.3f}")
# Logistic regression with the default 0.5 threshold (predict).model = LogisticRegression().fit(X_tr, y_tr)print(classification_report(y_test, model.predict(X_test), digits=3))
# Choose the threshold on the VALIDATION set (not the test set).p_val = model.predict_proba(X_val)[:, 1]ts = np.round(np.arange(0.05, 0.95, 0.05), 2)f1s = [f1_score(y_val, (p_val >= t).astype(int)) for t in ts]best_t = ts[int(np.argmax(f1s))]print(f"best threshold on validation: {best_t:.2f}")
# Score once on the test set with the chosen threshold.p_test = model.predict_proba(X_test)[:, 1]y_hat = (p_test >= best_t).astype(int)print(classification_report(y_test, y_hat, digits=3))The first run downloads Python, about 10 MB.
The test set contains 400 instances, including 22 positive samples (support column):
- Dummy model: Accuracy is 0.945 yet recall is 0.000—failing to capture a single positive case.
- Default logistic regression (): Accuracy is 0.960, barely 1.5 percentage points above the dummy model. Inspecting class
1reveals reality: precision is 1.000 but recall is only 0.273 (capturing merely 6 of 22 positive cases). The model is excessively timid. - Validation-tuned threshold (): Evaluated once on the held-out test set, recall jumps to 0.500 (11 of 22 caught), precision settles at 0.647, and class
1F1 rises from 0.429 to 0.564. Overall accuracy remains virtually flat (0.958 vs. 0.960). Relying on accuracy alone completely conceals this doubling in minority-class detection.
The bottom rows illustrate aggregation strategies. Under threshold 0.5, macro avg F1 is 0.704, whereas weighted avg is 0.949. Weighted averaging assigns overwhelming weight to class 0 (378 instances), concealing poor performance on the minority class. Macro averaging weights both classes equally, immediately highlighting the deficiency.
Common Pitfalls
Section titled “Common Pitfalls”Quick Check
Section titled “Quick Check”Summary and Further Reading
Section titled “Summary and Further Reading”Key Takeaways:
- Accuracy is easily distorted by class imbalance: a majority-class predictor matches the majority prevalence (70% on 20 patients, 94.5% in our synthetic experiment). Always compare against this baseline.
- A confusion matrix partitions errors into false alarms (FP) and missed detections (FN). penalizes false alarms, while penalizes misses. is their harmonic mean, tethered closely to the weaker score.
- The model outputs continuous probabilities ; selecting threshold is your choice. Raising cannot increase recall and typically raises precision. Prioritize recall when misses are catastrophic (medical screening); prioritize precision when false alarms are intolerable (spam filtering). Optimize on validation data.
- Precision–recall and ROC curves sweep across all thresholds. AUC represents the probability that a random positive instance is ranked above a random negative one; under severe imbalance, precision–recall curves provide more truthful feedback. For multi-class settings, macro averages treat all classes equally, weighted averages scale by support, and micro averages equate to accuracy.
Further Reading:
- Vũ Hữu Tiệp (2017). Machine Learning cơ bản, Bài 33: Các phương pháp đánh giá một hệ thống phân lớp. Vietnamese resource covering confusion matrices, ROC/AUC, precision–recall, F1, micro and macro averaging.
- Google (n.d.). Machine Learning Crash Course: Accuracy, recall, precision, and related metrics and ROC and AUC. Concise tutorials explaining trade-offs and the probabilistic ranking intuition behind AUC.
- scikit-learn developers (2007–2026). scikit-learn 1.8 User Guide: Metrics and scoring, Section 3.4.4. Formal definitions for
macro,micro,weighted, andzero_division. See also Section 3.3 Tuning the decision threshold detailingTunedThresholdClassifierCV. - Fawcett, T. (2006). An introduction to ROC analysis. Pattern Recognition Letters 27(8), 861–874. Foundational paper on ROC and AUC analysis.
- Saito, T., Rehmsmeier, M. (2015). The Precision-Recall Plot Is More Informative than the ROC Plot When Evaluating Binary Classifiers on Imbalanced Datasets. PLOS ONE 10(3), e0118432. Demonstrates why precision–recall curves are superior to ROC under extreme class imbalance.
Your browser is blocking storage. Your progress will be lost when you reload the page.
Content licensed under CC BY-NC-SA 4.0. Code under the MIT license.About