Classification Applications › Evaluation and Metrics
Language AI HandbookAll chapters Classification Applications › Evaluation and MetricsOne section · Sections in this chapter7 / 10 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Classification evaluation requires care about which metrics you report and what they mean.
Accuracy and Its Limitations
Accuracy, the fraction of correct predictions, is the most natural metric but fails in two important ways.
First, it treats all errors equally. Misclassifying a fraud report as an account inquiry has far higher cost than misclassifying an account inquiry as a fraud report. Applications with asymmetric error costs need weighted or asymmetric metrics.
Second, accuracy is misleading for imbalanced datasets. A classifier that always predicts the majority class in a 95/5 imbalance achieves 95% accuracy. That number is meaningless as an evaluation of the classifier's utility.
The combination of these two failures makes accuracy a particularly poor guide for systems where the economically important class is the rare one. In fraud detection, spam filtering, medical diagnosis, and content moderation, the class that matters is almost always the minority class. Reporting accuracy in these settings creates a false sense of security: a model with 98% accuracy can still be missing 40% of fraud cases.
Precision, Recall, and F1
The standard alternative to accuracy is the precision-recall family of metrics, evaluated per class and then aggregated.
For a class :
where:
- (True Positives): examples correctly predicted as class
- (False Positives): examples of other classes incorrectly predicted as class
- (False Negatives): examples of class incorrectly predicted as another class
Precision measures how often the model is right when it fires on class . Recall measures what fraction of the true class examples the model retrieves. F1 is their harmonic mean, penalizing models that sacrifice one to maximize the other. Note that Precision and Recall trade off: raising the decision threshold increases Precision but decreases Recall, and vice versa.
The harmonic mean matters here. If a model achieves 100% precision by predicting the positive class on only one example and getting it right, its F1 will be near zero because recall is near zero. If it achieves 100% recall by predicting positive for every example, its F1 will be low because precision will be near the base rate. F1 rewards balanced performance, which is usually what you want.
The macro-average F1 averages the per-class F1 scores with equal weight:
The weighted-average F1 weights each class by its support (number of examples):
where is the number of examples in class . Macro-F1 is more informative for imbalanced datasets because it gives equal importance to rare classes. Weighted-F1 reflects overall system performance weighted by class frequency.
The choice between macro and weighted F1 is a business decision disguised as a technical one. Weighted-F1 tells you how the system performs on average traffic. Macro-F1 tells you how the system performs on each category equally. If the rare categories (fraud, critical safety issues) are the ones that matter most, macro-F1 is the right headline metric, even though it is sensitive to performance on categories with very few examples.
import numpy as np
# Simulate classifier predictions on a 4-class problem with imbalance
np.random.seed(42)
# True labels: imbalanced distribution
true_labels = (
["check_balance"] * 80
+ ["transfer_funds"] * 50
+ ["pay_bill"] * 40
+ ["report_fraud"] * 15
)
# Simulate predictions with class-specific error rates
# Fraud detection is harder (fewer examples, higher confusion)
predicted_labels = []
error_rates = {
"check_balance": 0.05,
"transfer_funds": 0.10,
"pay_bill": 0.12,
"report_fraud": 0.25,
}
confusion_pairs = {
"check_balance": "transfer_funds",
"transfer_funds": "check_balance",
"pay_bill": "check_balance",
"report_fraud": "transfer_funds",
}
for label in true_labels:
if np.random.random() < error_rates[label]:
predicted_labels.append(confusion_pairs[label])
else:
predicted_labels.append(label)Classification Report:
precision recall f1-score support
check_balance 0.88 0.94 0.91 80
pay_bill 1.00 0.88 0.93 40
report_fraud 1.00 0.67 0.80 15
transfer_funds 0.82 0.90 0.86 50
accuracy 0.89 185
macro avg 0.93 0.84 0.87 185
weighted avg 0.90 0.89 0.89 185
Overall accuracy: 0.892The classification report reveals what overall accuracy hides: the fraud detection class (report_fraud) has significantly lower recall than the other classes because it has fewer training examples and higher confusion with other intents. The overall accuracy of approximately 90% looks reasonable, but the fraud recall of approximately 75% means one in four fraud reports is miscategorized. Whether that is acceptable depends on the application's risk tolerance, but reporting accuracy alone would have obscured this critical gap entirely.
The Generalization
When recall and precision are not equally important, you can generalize F1 to weight one more heavily than the other using the metric:
where:
- : weights recall more heavily than precision (useful when missing positives is costly, as in fraud or medical screening)
- : weights precision more heavily than recall (useful when false positives are costly, as in content recommendation or legal document review)
- : the standard F1 metric, treating precision and recall equally
In fraud detection, you might use to ensure the metric penalizes misses more than false alarms. In spam filtering, where users strongly object to legitimate email being marked as spam, you might use to penalize false positives more. The parameter makes the business tradeoff explicit and encodes it directly into the metric.
Key Parameters
The key modeling parameters for text classification systems are:
- model: The pre-trained backbone to fine-tune.
distilbert-base-uncased-finetuned-sst-2-englishis fast and suitable for binary sentiment. For zero-shot classification,cross-encoder/nli-deberta-v3-smallis compact and efficient;facebook/bart-large-mnliis larger and often more accurate but requires a 1.6GB download. For fine-tuning,bert-base-uncasedorroberta-baseare standard starting points. - device: The compute backend for inference.
-1forces CPU; use0for GPU when available. GPU inference is typically 10-30x faster for transformer models. - OOS_THRESHOLD: The confidence floor for out-of-scope rejection in intent detection. Values between 0.4 and 0.6 are typical; tune on a held-out OOS development set.
- ngram_range: For TF-IDF classifiers,
(1, 2)includes unigrams and bigrams, capturing local negation patterns. Extending to(1, 3)rarely helps and increases feature space substantially. - C (logistic regression): The inverse regularization strength. Smaller values produce stronger regularization.
C=1.0is a reasonable default; reduce to0.1for small datasets to prevent overfitting. - class_weight: Set to
'balanced'inLogisticRegressionorLinearSVCto automatically upweight rare classes proportional to their inverse frequency.