Mid-level 15 min · March 06, 2026

ML Evaluation Metrics — 99% Accuracy Missed All Fraud

A 99% accurate fraud detector missed all chargebacks due to zero recall.

N
Naren Founder & Principal Engineer

20+ years shipping production ML systems and the infrastructure behind them. Notes here come from systems that actually shipped.

Follow
Production
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Evaluate ML models using metrics derived from confusion matrix: TP, FP, FN, TN.
  • Accuracy = (TP+TN)/(total) — misleading for imbalanced data.
  • Precision = TP/(TP+FP) — how many predicted positives are correct.
  • Recall = TP/(TP+FN) — how many actual positives were found.
  • F1 = 2(PrecisionRecall)/(Precision+Recall) — balances both.
  • AUC-ROC measures separability across thresholds — higher is better (1.0 perfect, 0.5 random).
  • For multi-class, use macro, micro, or weighted F1 — pick based on class imbalance.
✦ Definition~90s read
What is ML Model Evaluation Metrics?

ML evaluation metrics are the quantitative tools you use to measure how well your model actually performs — not just on training data, but in the real-world scenarios where it will make decisions. The core problem they solve is that raw accuracy, while intuitive, is often dangerously misleading, especially when your data is imbalanced (e.g., 99% legitimate transactions, 1% fraud).

Imagine you built a spam filter.

A model that predicts 'not fraud' for every case achieves 99% accuracy but catches zero fraud — a catastrophic failure that evaluation metrics like precision, recall, and F1 score are designed to expose. These metrics force you to look beyond the aggregate and understand specific failure modes: false positives (flagging good customers as fraud) and false negatives (missing actual fraud).

In the MLOps ecosystem, evaluation metrics sit at the intersection of model development and deployment. They are not just academic — they directly inform business decisions, regulatory compliance, and cost trade-offs. For example, in fraud detection, a recall of 0.95 might be legally required even if precision drops to 0.70, because missing fraud costs more than annoying customers.

Alternatives like AUC-ROC give you a threshold-independent view of model discrimination ability, while metrics like log loss or Brier score measure probabilistic calibration. You should not rely on a single metric; instead, you must choose a suite based on your specific cost structure and business context.

Concretely, precision answers 'of all the cases we flagged as fraud, how many were actually fraud?' while recall answers 'of all actual fraud cases, how many did we catch?' The F1 score is their harmonic mean, penalizing extreme imbalance between the two. ROC curves plot true positive rate vs. false positive rate across all thresholds, and AUC-ROC summarizes this into a single number — but beware: AUC can be misleading on highly imbalanced data, where precision-recall curves are more informative.

Tools like scikit-learn, MLflow, and Weights & Biases provide these calculations out of the box, but the hard part is interpreting them in your specific deployment context.

Plain-English First

Imagine you built a spam filter. You show it 1,000 emails and it sorts them into 'spam' or 'not spam'. But how do you grade its work? Just counting how many it got right isn't enough — because if only 10 emails were actually spam and your filter calls everything 'not spam', it's still 99% right while being completely useless. ML evaluation metrics are the report card system that catches this kind of trick and tells you whether your model is genuinely smart or just getting lucky.

Every ML model you ship into production makes decisions that cost real money or carry real risk. A fraud detector that misses fraud is a liability. A cancer screener that cries wolf scares patients and wastes resources. Picking the wrong metric is one of the costliest MLOps mistakes — and it happens constantly because teams default to accuracy without checking what accuracy measures in their context.

Here's the thing: a single number like '94% accuracy' hides everything that matters. It doesn't show whether your model fails on the minority class, whether its confidence scores are calibrated, or how performance changes as you move the decision threshold. Those blind spots are exactly where production models go wrong — not because the model is bad, but because it was optimised for the wrong thing from the start.

By the end you'll read a confusion matrix without hesitation, choose the right metric for any ML problem, implement accuracy, precision, recall, F1, ROC-AUC, and PR-AUC in Python from scratch, and explain the trade-offs in a job interview. Everything builds around a single realistic dataset so you see how each metric paints a different picture of the same model.

Why 99% Accuracy Missed All Fraud

ML model evaluation metrics are quantitative measures that assess how well a model's predictions match reality. The core mechanic is comparing predicted outcomes against ground truth labels using a confusion matrix: true positives, false positives, true negatives, and false negatives. Accuracy alone—(TP+TN)/(TP+TN+FP+FN)—is dangerously misleading when classes are imbalanced. In a fraud detection dataset with 0.1% fraud, a model that predicts 'not fraud' for every transaction achieves 99.9% accuracy yet catches zero fraud. Precision (TP/(TP+FP)) and recall (TP/(TP+FN)) expose this failure: precision tells you how many flagged frauds are real, recall tells you how many real frauds you caught. The F1-score, the harmonic mean of precision and recall, collapses both into a single metric that penalizes extreme imbalance. In production, you must also consider latency (inference time per record) and throughput (records per second) because a model that scores perfectly but takes 500ms per transaction is useless for real-time fraud blocking. Use precision-recall curves when the positive class is rare; use ROC-AUC only when you care equally about both classes. The choice of metric directly determines what the model optimizes—and what it misses.

Accuracy Trap
A 99% accurate fraud model can be worse than random if it never predicts fraud. Always check the confusion matrix before trusting a single number.
Production Insight
In a real-time payment fraud system, a team deployed a model with 99.8% accuracy but recall of 0.02 — it missed 98% of actual frauds, causing $2M in losses over a weekend before the metric was caught.
The symptom: fraud alerts dropped to near zero while chargebacks spiked, yet the dashboard showed 'accuracy improving'.
Rule of thumb: for any binary classifier with <5% positive class, never deploy without monitoring precision and recall at the decision threshold you actually use.
Key Takeaway
Accuracy is only meaningful when classes are balanced — otherwise it hides model failure.
Always evaluate with precision, recall, and F1 for imbalanced problems; use the confusion matrix as your first diagnostic.
The metric you optimize determines what the model learns — choose metrics that reflect the real cost of false positives vs. false negatives.
ML Evaluation Metrics: Accuracy vs. Fraud Detection THECODEFORGE.IO ML Evaluation Metrics: Accuracy vs. Fraud Detection Why 99% accuracy fails and which metrics to use instead Accuracy 99% accuracy misses all fraud Precision & Recall Trade-off between false positives and false negatives F1 Score Harmonic mean balancing precision and recall ROC Curve & AUC-ROC Threshold-independent performance measure Precision-Recall Curve Better for imbalanced datasets Multi-Class Metrics Macro, micro, and weighted averaging ⚠ Accuracy is dangerous for imbalanced classes Always use precision-recall or F1 for fraud detection THECODEFORGE.IO
thecodeforge.io
ML Evaluation Metrics: Accuracy vs. Fraud Detection
Ml Model Evaluation Metrics

ML Model Evaluation Metrics is

ML Model Evaluation Metrics is a core concept in ML / AI. Rather than starting with a dry definition, let's see it in action and understand why it exists.

At its core, evaluation metrics quantify how well a machine learning model performs on a given dataset. The simplest metric is accuracy — the fraction of correct predictions. But as anyone who has worked on fraud detection, medical diagnosis, or any imbalanced dataset knows, accuracy can lie. The real power of evaluation metrics comes from understanding the full picture: not just how many predictions were correct, but how the model behaves for each class, how confident it is, and how its performance changes as you adjust decision thresholds.

We'll start with the confusion matrix, the foundation for all classification metrics. Then we'll dive into each metric, see how they're computed, when they're useful, and when they break. Every example uses the same synthetic dataset so you can compare metrics directly.

io_thecodeforge/confusion_matrix.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from io_thecodeforge.metrics import confusion_matrix, classification_report

# Create an imbalanced dataset (5% positive class)
X, y = make_classification(n_samples=10000, weights=[0.95, 0.05], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

# Confusion matrix
cm = confusion_matrix(y_test, y_pred)
print('Confusion Matrix:\n', cm)
# Full report
print(classification_report(y_test, y_pred, target_names=['Legitimate', 'Fraud']))
Forge Tip:
Type this code yourself rather than copy-pasting. The muscle memory will help it stick.
Production Insight
Many teams only log accuracy to their dashboard. When fraud detection fails, they have no early warning.
Always log the full confusion matrix and per-class metrics to catch silent model degradation.
Rule: if you only track accuracy, you're blind to model failure.
Key Takeaway
The confusion matrix is the single most informative evaluation output.
Master it first, then derive all other metrics from it.
Accuracy tells you nothing about where your model fails — the matrix does.

Accuracy — The Most Dangerous Metric in MLOps

Accuracy = (TP + TN) / (TP + TN + FP + FN).

It's intuitive: what fraction of predictions did the model get right? For balanced datasets this works fine. But in most real-world ML problems, classes are imbalanced — sometimes severely. Consider a credit card fraud dataset where 0.1% of transactions are fraudulent. A model that predicts 'not fraud' for every single transaction achieves 99.9% accuracy. That sounds great, but it caught zero fraud.

Accuracy is also sensitive to the distribution of classes in the test set. If your test set doesn't reflect production class ratios, accuracy gives a false sense of performance. That's why you should never use accuracy as your primary metric when: - The minority class is what you care about (fraud, disease, churn). - The cost of false negatives is high. - The dataset is imbalanced (most real-world binary classification).

In production, we often see accuracy reported in dashboards with a green checkmark. That's a trap. If the model's accuracy stays high but recall drops, you won't notice until the financial damage is done.

One practical fix: compute a cost matrix where each error type (FP vs FN) has a dollar value. Then optimise for minimum cost, not maximum accuracy. This maps business reality to model selection.

io_thecodeforge/accuracy_trap.pyPYTHON
1
2
3
4
5
6
7
8
9
from io_thecodeforge.metrics import accuracy_score, recall_score

# Simulate : 95% legitimate, 5% fraud
# Model predicts all legitimate
y_true = [0]*950 + [1]*50
y_pred = [0]*1000

print('Accuracy:', accuracy_score(y_true, y_pred))  # 0.95
print('Recall:', recall_score(y_true, y_pred))      # 0.0
Production Watch
If your business metric is 'fraud dollars caught', accuracy is irrelevant. Map business goals to the right metric — usually recall for catching bad events, precision for reducing false alerts.
Production Insight
Model dashboards that only show accuracy hide model collapse.
One team reported 98% accuracy for weeks until a quarterly audit revealed recall had dropped to 15%.
Rule: never let accuracy be the only metric on your dashboard.
Key Takeaway
Accuracy is only safe when classes are balanced and errors cost equally.
For imbalanced or asymmetric-cost problems, accuracy is a liability.
Always pair accuracy with precision and recall.

Precision and Recall — The Trade-off You Can't Ignore

Precision = TP / (TP + FP). It answers: when the model predicts positive, how often is it correct? Recall = TP / (TP + FN). It answers: of all actual positives, how many did the model find?

These two metrics are in tension. Increasing one usually decreases the other. For example, in a spam filter: - High precision means you almost never mark a legitimate email as spam (low FP), but you might miss some spam. - High recall means you catch almost all spam, but you also flag some legitimate emails.

Which matters more depends on your problem. For cancer screening, you want high recall — missing a cancer case is far worse than a false alarm. For recommending content to users, you want high precision — showing irrelevant content hurts user trust.

In production, you often choose a trade-off by adjusting the decision threshold. The default threshold (0.5) is rarely optimal for real-world costs.

A common approach: plot precision-recall curve over all thresholds and pick the point that maximises some business utility function (e.g., profit).

io_thecodeforge/precision_recall_tradeoff.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from io_thecodeforge.metrics import precision_score, recall_score
from io_thecodeforge.calibration import adjust_threshold

# Get predicted probabilities
y_prob = model.predict_proba(X_test)[:, 1]

# Default threshold 0.5
print('Precision:', precision_score(y_test, y_prob > 0.5))
print('Recall:', recall_score(y_test, y_prob > 0.5))

# Lower threshold to catch more fraud
y_pred_low = y_prob > 0.3
print('\nWith threshold 0.3:')
print('Precision:', precision_score(y_test, y_pred_low))
print('Recall:', recall_score(y_test, y_pred_low))
Precision vs Recall Mental Model
  • Precision: 'I found 10 frauds, 8 were real frauds, 2 were false alarms' → 0.8 precision.
  • Recall: 'There were really 20 frauds, I caught 8' → 0.4 recall.
  • Trade-off: to improve recall, you lower the bar for fraud flagging, which brings in more false alarms (lowers precision).
Production Insight
In a payment fraud system, the team required precision >95% but recall was 30%. They were missing most fraud.
Lowering the threshold to achieve 70% recall dropped precision to 85% — acceptable because each caught fraud saved $50 vs a false alarm cost of $0.10.
Rule: tune thresholds using cost matrices, not arbitrary numbers.
Key Takeaway
Precision and recall are always a trade-off — there's no free lunch.
Choose based on the cost of false positives vs false negatives.
Always compute precision and recall together; never report one without the other.
Choose Precision vs Recall Based on Business Cost
IfFalse negatives are expensive (e.g., disease screening)
UseOptimise for recall. Accept lower precision.
IfFalse positives are expensive (e.g., spam filter for VIP emails)
UseOptimise for precision. Accept lower recall.
IfBoth types of errors carry similar cost
UseUse F1-score as the primary metric. Tune threshold on validation set.

F1 Score — The Harmonic Mean That Balances

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

F1 is a single metric that combines precision and recall. Because it's a harmonic mean (not arithmetic), it's heavily penalised when either precision or recall is low. A model with precision=1.0 and recall=0.0 gives F1=0, not 0.5. This makes F1 a good default for imbalanced datasets when you care about both precision and recall.

But F1 is not a silver bullet. If your business cares only about recall (e.g., catching disease), F1 will push you to improve precision at the cost of recall — potentially losing real cases. Similarly, if false positives are extremely costly (e.g., missile launch alerts), F1 will try to balance, but you really need high precision.

There's also the F-beta metric, which generalises F1 by weighting recall more (beta > 1) or precision more (beta < 1). F2 is common for recall-focused problems.

When comparing models, don't just look at F1 — always inspect precision and recall components. A model with lower F1 but better recall may be the right choice for your business.

io_thecodeforge/f1_score.pyPYTHON
1
2
3
4
5
6
from io_thecodeforge.metrics import f1_score, precision_score, recall_score
# Assume y_test and y_pred from previous
print('Precision:', precision_score(y_test, y_pred))
print('Recall:', recall_score(y_test, y_pred))
print('F1:', f1_score(y_test, y_pred))
# Note: the harmonic mean penalizes extreme imbalance
When F1 is useful
Use F1 when you need a single score to compare models and both precision and recall matter. But always check the individual components — F1 can hide a serious imbalance if not examined.
Production Insight
One team used F1 to select a model and deployed it. F1 was 0.85, but in production the model had very high precision (0.98) and very low recall (0.30). They had chosen a model that sacrificed recall for precision, which was the opposite of what the business needed.
Lesson: always inspect precision and recall before trusting F1.
Rule: pick the primary metric based on business context, then monitor all three.
Key Takeaway
F1 is a good summary when precision and recall are equally important.
But a high F1 can mask a very lopsided precision-recall trade-off.
Always look at the components before trusting the composite.

ROC Curve and AUC-ROC — Threshold Independence

The Receiver Operating Characteristic (ROC) curve plots the true positive rate (recall) against the false positive rate (1 - specificity) at every possible threshold. The Area Under the ROC Curve (AUC-ROC) summarises this into a single number: the probability that the model ranks a random positive instance higher than a random negative instance.

AUC-ROC is threshold-independent — it evaluates the model's ability to separate classes regardless of where you set the cutoff. A perfect model has AUC-ROC = 1.0; a random model has 0.5. AUC-ROC is excellent for comparing classifiers, especially when the class distribution is balanced or you don't know the costs yet.

However, AUC-ROC can be misleading when the dataset is highly imbalanced. Because it includes FPR (which uses true negatives), and if negatives dominate, FPR will be tiny even if the model is mediocre. In such cases, use the Precision-Recall curve (PR-AUC) instead. PR-AUC focuses on the minority class and is more informative for imbalanced datasets.

A common mistake: treating AUC-ROC as a deployment performance metric. It's a ranking metric — you still need to pick a threshold that optimises your business objective.

io_thecodeforge/roc_auc.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from sklearn.metrics import roc_curve, auc, roc_auc_score
import matplotlib.pyplot as plt

# Assume we have y_test and model probabilities from previous example
y_prob = model.predict_proba(X_test)[:, 1]
fpr, tpr, _ = roc_curve(y_test, y_prob)
roc_auc = auc(fpr, tpr)

print(f'AUC-ROC: {roc_auc:.3f}')

# Plot ROC curve
plt.plot(fpr, tpr, label=f'ROC curve (AUC = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], 'k--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend()
plt.show()
ROC vs PR Curve
For imbalanced classes (e.g., <10% positives), prefer the Precision-Recall curve. AUC-ROC can overestimate performance when negatives dominate.
Production Insight
A team used AUC-ROC to select a model for fraud detection (1% fraud rate). Score was 0.99. In production, recall was only 20% because the model was good at ranking but the threshold was set incorrectly to maintain the high AUC.
AUC-ROC measures ranking, not deployment performance.
Rule: after ranking well, always tune the threshold on business costs.
Key Takeaway
AUC-ROC tells you if the model can separate classes — not how to set the threshold.
For imbalanced data, examine PR-AUC as well.
A high AUC-ROC does not guarantee good precision/recall at your chosen threshold.

Precision-Recall Curve: When AUC-ROC Deceives

The Precision-Recall (PR) curve plots precision against recall at every threshold, completely ignoring true negatives. This makes it far more sensitive to the minority class. For highly imbalanced datasets (e.g., <10% positives), AUC-ROC can remain optimistically high because FPR stays small due to the sheer number of negatives. PR-AUC (area under the PR curve) better reflects the model's real-world performance on the class you actually care about.

A typical trap: a model achieves AUC-ROC 0.99 on a 1% fraud dataset, but PR-AUC is only 0.55. The model ranks positives well (hence high ROC) but at any usable threshold, it either misses fraud or generates too many false alarms (low PR). If you only monitor ROC, you'd ship a broken model.

Always include PR-AUC in your evaluation dashboard when the minority class matters. It catches failures that ROC silently ignores.

Here's the math: AUC-ROC uses FPR which has a denominator of total negatives. When negatives outnumber positives 99:1, the FPR can be low even if the model is mediocre on the positive class. PR-AUC uses precision, which has a denominator of predicted positives — it's directly affected by the minority class. That's why PR-AUC is the honest metric for rare events.

io_thecodeforge/pr_auc.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from sklearn.metrics import precision_recall_curve, average_precision_score
import matplotlib.pyplot as plt

y_prob = model.predict_proba(X_test)[:, 1]
precision, recall, _ = precision_recall_curve(y_test, y_prob)
pr_auc = average_precision_score(y_test, y_prob)

print(f'PR-AUC (Average Precision): {pr_auc:.3f}')

plt.plot(recall, precision, label=f'PR curve (AP = {pr_auc:.2f})')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall Curve')
plt.legend()
plt.show()
When to Use PR Curve
Use PR curve when positives are rare. ROC can overestimate performance because it includes True Negatives (which dominate). PR-AUC is the metric that reflects minority-class performance.
Production Insight
In a fraud detection system, AUC-ROC dropped from 0.99 to 0.98 after a retrain. The team ignored it — 'wouldn't have mattered'.
PR-AUC had dropped from 0.85 to 0.60 — the model was silently failing on fraud cases.
Rule: always monitor PR-AUC for imbalanced classes; it will catch failures ROC misses.
Key Takeaway
For imbalanced data, PR-AUC reveals what ROC hides.
A high AUC-ROC does not guarantee good precision on rare events.
Add PR-AUC to your model dashboard — it will catch failures ROC misses.

Multi-Class Evaluation Metrics: Macro, Micro, and Weighted F1

Production models often predict more than two classes: digit recognition (0-9), sentiment (positive/neutral/negative), or image classification (dog, cat, bird). For multi-class problems, you need to aggregate per-class metrics into a single number. Three common aggregation methods exist:

  • Macro F1: Compute F1 for each class independently, then take the arithmetic mean. All classes count equally, regardless of their frequency. Useful when you care about performance on every class equally, even rare ones. But it can be heavily influenced by classes with very few samples.
  • Micro F1: Aggregate all TP, FP, FN across all classes, then compute F1 globally. This is equivalent to computing accuracy on a per-instance basis but expressed as F1. It's dominated by the most frequent class — good if class imbalance is not a concern.
  • Weighted F1: Compute F1 per class, then take weighted average by the number of true instances per class. It accounts for class imbalance and is often the most realistic for production. scikit-learn's f1_score(average='weighted') uses this.

Choose based on your business needs. If rare classes matter (e.g., detecting rare diseases), use macro F1. If you want a single number that reflects overall performance, use weighted F1. Micro F1 is rarely used outside multi-label problems.

io_thecodeforge/multi_class_metrics.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
from io_thecodeforge.metrics import f1_score, classification_report

# Example: 3-class problem
y_true = [0, 1, 2, 0, 1, 2, 0, 0, 1]
y_pred = [0, 1, 1, 0, 2, 2, 0, 0, 1]

print('Macro F1:', f1_score(y_true, y_pred, average='macro'))
print('Micro F1:', f1_score(y_true, y_pred, average='micro'))
print('Weighted F1:', f1_score(y_true, y_pred, average='weighted'))
print('\nPer-class report:')
print(classification_report(y_true, y_pred))
Production Trap
If you have a class with very few samples, macro F1 can be misleadingly low (or high) due to variance. Consider a minimum sample count threshold per class before including it in macro or weighted calculations.
Production Insight
A model for predicting customer intent had three classes: 'buy', 'browse', 'leave'. The team used macro F1 and got 0.92. But the 'buy' class (only 2% of data) had recall 0.10 — macro F1 hid this because the class was small. Switching to weighted F1 gave 0.88, which better reflected the majority class performance but still didn't alert them to the minority failure.
Rule: for multi-class, always look at per-class metrics. Use macro F1 if you care about rare classes, weighted F1 if you want an overall summary. Monitor both.
Key Takeaway
Macro F1 treats all classes equally — good for rare classes.
Weighted F1 respects class frequencies — better for overall summary.
Micro F1 is equivalent to accuracy in single-label problems — not useful.
Always inspect per-class metrics before trusting aggregated numbers.

Choosing the Right Evaluation Strategy: A Decision Framework

You've seen each metric individually. Now the hard part: picking the right one for your problem. The answer always starts with business context, not data statistics.

Start by answering two questions: 1. What is the cost of a false negative vs a false positive? 2. How rare is the positive class?

If FN cost >> FP cost (disease, fraud, safety) → prioritise recall. Use recall as primary, PR-AUC for model selection. If FP cost >> FN cost (spam, recommendation) → prioritise precision. Use precision at a fixed recall threshold. If costs are similar → use F1, but still check components. For model comparison before threshold tuning → use AUC-ROC or PR-AUC (prefer PR for imbalanced).

In production, define a metric suite: confusion matrix, precision, recall, F1, AUC-ROC, PR-AUC. Pick one primary, set minimum acceptable thresholds for others. Alert on any metric crossing threshold.

The biggest mistake? Changing metrics during model development. Pick your evaluation approach before you train a single model. Let the business goals drive the choice, not the other way around.

io_thecodeforge/metric_selection.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Not runnable — conceptual decision framework
# Define costs
cost_fn = 100  # false negative cost (missed disease)
cost_fp = 1    # false positive cost (unnecessary test)

# Choose threshold that minimizes total cost
def total_cost(y_true, y_prob, threshold):
    y_pred = y_prob > threshold
    fp = ((y_pred == 1) & (y_true == 0)).sum()
    fn = ((y_pred == 0) & (y_true == 1)).sum()
    return cost_fp * fp + cost_fn * fn

# Evaluate thresholds
def select_threshold(y_true, y_prob):
    thresholds = np.linspace(0, 1, 100)
    costs = [total_cost(y_true, y_prob, t) for t in thresholds]
    return thresholds[np.argmin(costs)]
The Business-First Mental Model
  • Fraud detection: 'How much fraud did we catch?' → recall, PR-AUC
  • Content moderation: 'How many false flags upset users?' → precision, precision at k
  • Medical diagnosis: 'How many cases did we miss?' → recall, F2-score
  • Churn prediction: 'How many at-risk customers did we identify?' → recall + lift
Production Insight
One team evaluated models using AUC-ROC and picked one with 0.99. They deployed, and the fraud catch rate was 15%.
They had never mapped business KPIs to metrics. Once they switched to PR-AUC, they selected a model with 80% recall.
Rule: define business success before training; let metrics serve the business, not the other way around.
Key Takeaway
The best metric is the one that aligns with your business cost structure.
Never start with accuracy or F1 — start with the cost of each error type.
If you haven't defined business goals, no metric will save you.
Choose Primary Metric Based on Business Context
IfFalse negatives are expensive and positives are rare
UsePrimary: Recall. Use PR-AUC for model selection. Set minimum recall threshold.
IfFalse positives are expensive (e.g., alert fatigue)
UsePrimary: Precision. Use precision at k or fixed recall. Monitor recall floor.
IfBoth error types have similar cost
UsePrimary: F1-score. Use weighted F1 for multi-class. Inspect components.
IfModel is still in exploration phase, no business cost defined yet
UseUse AUC-ROC or PR-AUC for initial model selection. Tune threshold later.

Threshold Tuning: From Model Scores to Business Decisions

All the metrics we've discussed depend on where you set the decision threshold — the probability cutoff above which you predict positive. The default 0.5 is rarely optimal. Tuning the threshold is where you turn a good ranking model into a deployed system that actually delivers business value.

Here's your workflow: 1. Get predicted probabilities on a validation set (never the test set). 2. Plot precision and recall across thresholds. 3. Compute the total cost at each threshold using your cost matrix. 4. Pick the threshold that minimises expected cost.

This approach works for any binary problem. It also lets you adjust the trade-off as business conditions change — e.g., if the cost of fraud increases, you lower the threshold to catch more cases.

A common production mistake: freezing the threshold at deployment and never revisiting it. Thresholds should be re-evaluated quarterly or whenever class distributions shift significantly.

For multi-class problems, you may need one threshold per class or use a global confidence cutoff. The same principle applies — optimise each threshold for the cost structure of that class's errors.

io_thecodeforge/threshold_tuning.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import numpy as np
from sklearn.metrics import precision_recall_curve

# Validation set
y_prob_val = model.predict_proba(X_val)[:, 1]
precisions, recalls, thresholds = precision_recall_curve(y_val, y_prob_val)

# Cost assumptions
cost_fn = 50  # missed fraud costs $50
cost_fp = 1   # false alarm costs $1

# Total cost for each threshold
costs = []
for t in thresholds:
    y_pred = (y_prob_val >= t).astype(int)
    fp = ((y_pred == 1) & (y_val == 0)).sum()
    fn = ((y_pred == 0) & (y_val == 1)).sum()
    costs.append(cost_fp * fp + cost_fn * fn)

best_idx = np.argmin(costs)
print(f'Optimal threshold: {thresholds[best_idx]:.2f}')
print(f'Precision: {precisions[best_idx]:.2f}')
print(f'Recall: {recalls[best_idx]:.2f}')
Threshold Gotcha
Never tune the threshold on the test set — that leaks information. Use a separate validation set or cross-validation. The test set is for final evaluation only.
Production Insight
A ride-sharing company tuned threshold once and deployed. After six months, the fraud rate doubled, but the model still performed well on ranking (AUC unchanged). The threshold needed to be lowered, but no one monitored it.
Result: millions lost to fraud before the quarterly review caught the shift.
Rule: automate threshold monitoring with a scheduled validation pipeline.
Key Takeaway
The default threshold of 0.5 is almost never optimal.
Tune threshold using a cost matrix on a validation set.
Revisit the threshold whenever class distribution or business costs change.

Monitoring Metrics in Production: What to Track and When to Alert

After you deploy, metrics drift. The model that performed well on your test set will eventually degrade because the world changes. Effective production monitoring is a combination of metrics and alerting.

Track these for every model in production
  • Confusion matrix aggregates: daily TP, FP, FN, TN rates. This is the most informative single view.
  • Precision, Recall, F1: per class, with rolling 7-day windows.
  • AUC-ROC and PR-AUC: weekly, to catch ranking degradation early.
  • Prediction confidence distribution: compare to training distribution via KS statistic.
  • Feature drift: track distribution of key features; alert on drift.
  • Data quality metrics: missing values, unexpected categories, schema violations.
Set up alerts with thresholds
  • Any per-class recall drops below 70% (or your business minimum).
  • PR-AUC drops by >0.05 in a week.
  • KS statistic on prediction scores exceeds 0.15.
  • A class that had F1 >0.9 drops to <0.6.

When an alert fires: pause automated rollouts, rollback the model if necessary, and debug using the guides above.

io_thecodeforge/production_monitoring.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Not runnable — production monitoring skeleton
from io_thecodeforge.monitoring import (
    ModelMonitor, DataDriftDetector, MetricTracker
)

monitor = ModelMonitor(
    model_id="fraud_v2",
    metrics=["precision", "recall", "f1", "pr_auc"],
    alert_thresholds={
        "recall_class_1": 0.7,
        "pr_auc": 0.05  # drop threshold
    },
    drift_detector=DataDriftDetector()
)

# After each prediction batch:
monitor.log_batch(y_true, y_pred, y_prob, features)

# Weekly check:
report = monitor.weekly_report()
if report.alerts:
    # Trigger rollback or investigation
    print(f"Alerts: {report.alerts}")
Forge Tip:
Don't just track metrics — track the gaps between train, validation, and production metrics. A big gap is your earliest warning sign of drift.
Production Insight
A team had dashboards for every metric but no alerts. The PR-AUC dropped from 0.8 to 0.4 over three weeks. No one noticed because no one looked at the dashboard daily.
They lost $500k before the quarterly review caught it.
Rule: never monitor without alerting. Use absolute thresholds and rate-of-change alerts.
Key Takeaway
Monitoring without alerting is just data collection.
Track confusion matrix, PR-AUC, and feature drift at minimum.
Set alerts for recall and PR-AUC drops — those are the earliest signals of failure.

Log Loss (Cross-Entropy): Probabilistic Evaluation Metric

Log loss, also known as cross-entropy loss, measures the performance of a classification model where the output is a probability between 0 and 1. Unlike accuracy or F1 which only care about the final binary decision, log loss penalises confident wrong predictions more than uncertain ones. That makes it the go-to metric when you need well-calibrated probabilities — for example, in ranking systems, risk scoring, or anytime you feed predictions into a downstream decision pipeline.

The formula for binary log loss: - (1/N) Σ [y log(p) + (1-y) * log(1-p)], where p is the predicted probability and y is the true label. A perfect model has log loss of 0. A model that predicts p=0.5 for everything gets log loss of about 0.693 (the natural log of 2).

In practice, log loss is harder to interpret than accuracy because you need a baseline comparison. Always compare against a naive model (e.g., always predict the majority class) or use a normalised version like pseudo-R².

One production trap: log loss is sensitive to extreme predictions. If your model outputs a probability of 0.9999 for a wrong prediction, log loss skyrockets. Some teams clip probabilities to [0.001, 0.999] to avoid infinite loss. That's a sign the model isn't calibrated — fix the calibration, don't just clip the output.

io_thecodeforge/log_loss_example.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from sklearn.metrics import log_loss
import numpy as np

# Example: perfect model
y_true = [0, 1, 0, 1]
y_prob_perfect = [0.01, 0.99, 0.01, 0.99]
print('Log loss (perfect):', log_loss(y_true, y_prob_perfect))

# Example: confident wrong predictions
y_prob_confident_wrong = [0.99, 0.01, 0.99, 0.01]
print('Log loss (confident wrong):', log_loss(y_true, y_prob_confident_wrong))

# Example: uncertain predictions (always 0.5)
y_prob_uncertain = [0.5, 0.5, 0.5, 0.5]
print('Log loss (uncertain):', log_loss(y_true, y_prob_uncertain))

# Baseline: always predict majority class (class 0)
baseline_prob = [1 - np.mean(y_true)] * len(y_true)
print('Log loss (baseline):', log_loss(y_true, baseline_prob))
When to Use Log Loss
Use log loss when you care about probability calibration — not just the hard decision. It's the default loss for classification neural networks. But don't use it as the only metric; always pair with F1 or AUC for a complete picture.
Production Insight
A team trained a churn prediction model and optimised it using accuracy. The model had good accuracy but terrible log loss — it was overconfident on its predictions. When they deployed, the business team couldn't trust the risk scores because the probabilities were poorly calibrated.
Rule: if downstream systems use your probabilities, monitor log loss and calibrate outputs.
Fix: apply Platt scaling or isotonic regression to calibrate.
Key Takeaway
Log loss penalises confident mistakes — it's the metric for probability quality.
Always compare log loss to a baseline (e.g., naive prediction).
If log loss is high but F1 is fine, your probabilities are probably uncalibrated.

Model Selection and Validation: Avoiding the Metric-Based Trap

Picking a model based on a single metric from one test set is like buying a car based on horsepower — you miss everything about drivability and maintenance. Cross-validation and proper model selection are essential to get a reliable picture of performance.

Use stratified k-fold cross-validation especially for imbalanced datasets. This ensures each fold maintains the class distribution. Compute the metric of interest on each fold and report mean ± std. A low variance across folds means the model is stable.

Avoid data leakage between folds and between train/validation/test sets — any feature that uses information from the future or from the test set will inflate metrics. Common leak sources: scaling before split, using target encoding on the full dataset, or including time-based features incorrectly.

Hold out a proper test set that is never used for any decision — no threshold tuning, no feature selection, no hyperparameter tuning. If you tune anything on the test set, you are cheating yourself.

One practical framework: 70% train, 15% validation (for threshold tuning), 15% test (for final evaluation). Or use nested cross-validation for small datasets.

io_thecodeforge/model_selection.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.ensemble import RandomForestClassifier
import numpy as np

X, y = make_classification(n_samples=5000, weights=[0.9, 0.1], random_state=42)

cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
model = RandomForestClassifier(random_state=42)

scores = cross_val_score(model, X, y, cv=cv, scoring='f1')
print(f'F1 across folds: {scores}')
print(f'Mean F1: {np.mean(scores):.3f} +/- {np.std(scores):.3f}')
Leak vigilance
Always fit your scaler or preprocessor on the training fold only, never on the entire dataset before cross-validation. Use sklearn Pipelines to enforce this.
Production Insight
A startup used a single train/test split to select a model. The model achieved 0.95 F1 on the test set. In production, F1 dropped to 0.60. Why? The test set had a different class distribution due to a random split that happened to be lucky. They had no cross-validation to detect variance.
Rule: always use cross-validation — a single split can lie.
Fix: use stratified k-fold and report variance.
Key Takeaway
Cross-validation gives you the real performance, not a lucky test split.
Never make decisions based on a single train/test split.
Report mean and std across folds — high std means the model is unstable.

Business Alignment: From Metrics to Decision Making

The most expensive mistake in ML is optimising a metric that doesn't map to business outcomes. You can have a model with perfect F1 but if it doesn't move the business needle, it's worthless.

Step 1: Define the business objective. Is it revenue, cost savings, customer retention, or user satisfaction? Step 2: Translate to model metric. For fraud: estimated dollars prevented. For churn: number of customers proactively retained. Step 3: Build a cost matrix. Assign dollar values to TP, FP, FN, TN. Then the optimal model is not the one with highest F1 or AUC — it's the one with the highest expected value. Step 4: Use a decision threshold that maximises business value. This is often different from the threshold that maximises F1. Step 5: Validate offline before online. Use historical data to simulate the business impact of your model at different thresholds.

Many teams skip to step 5 with a metric they copied from a blog post. Don't. Ground every decision in business reality.

io_thecodeforge/business_alignment.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Business impact simulation
# Assume each true positive (fraud caught) saves $100
# Each false positive (false alarm) costs $5
# Each false negative (missed fraud) costs $100
# Each true negative costs $0

value_per_tp = 100
cost_per_fp = -5
cost_per_fn = -100

def compute_business_value(y_true, y_pred):
    tp = ((y_pred == 1) & (y_true == 1)).sum()
    fp = ((y_pred == 1) & (y_true == 0)).sum()
    fn = ((y_pred == 0) & (y_true == 1)).sum()
    return tp * value_per_tp + fp * cost_per_fp + fn * cost_per_fn

# Evaluate across thresholds and pick the one with max value
The Value-First Mental Model
  • Map each cell of the confusion matrix to a dollar value.
  • Use that to compute expected value per prediction.
  • Select the threshold and model that maximise total business value.
  • Example: a fraud model with recall 0.7 and precision 0.5 might be more profitable than one with recall 0.9 and precision 0.2.
Production Insight
A team deployed a model with F1=0.92, but the business actually needed high precision to avoid annoying customers. The model had high recall but low precision, generating complaints. After switching to a precision-focused model with F1=0.80, customer satisfaction went up.
Rule: let business value, not metric value, drive the model you ship.
Key Takeaway
Business value is the ultimate metric.
Translate business objectives to confusion matrix costs.
Pick the model that maximises business value, not F1 or AUC.

Regression Metrics: When Your Model Predicts Continuous Values

You've been shipping classification models for months. Now your team launches a demand forecasting system. Classification metrics won't save you here. You need regression metrics. Mean Absolute Error (MAE) tells you the average prediction error in original units. It's interpretable. Your business stakeholders understand "our forecast is off by $500 on average." Mean Squared Error (MSE) punishes large errors quadratically. That single outlier that crashed your model at 3 AM? MSE catches it. Root Mean Squared Error (RMSE) brings MSE back to original units for comparison. Root Mean Squared Logarithmic Error (RMSLE) is your friend when predictions span multiple orders of magnitude — like predicting sales during Black Friday versus a Tuesday afternoon. R-squared (R²) measures variance explained by your model. A value of 0.85 means your model explains 85% of the variance. But here's the trap: R² always increases with more features. Use adjusted R² for feature selection. Never deploy a regression model with only MAE. You'll miss the outliers that burn your production pipeline.

inventory_forecast_eval.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// io.thecodeforge
import numpy as np
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

y_true = np.array([1200, 4500, 3200, 890, 15000])
y_pred = np.array([1150, 4700, 3000, 950, 13000])

mae = mean_absolute_error(y_true, y_pred)
mse = mean_squared_error(y_true, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_true, y_pred)

print(f"MAE: {mae:.2f} units")  # Average error in original units
print(f"MSE: {mse:.2f}")        # Catches outlier impact
print(f"RMSE: {rmse:.2f} units") # Back to interpretable scale
print(f"R²: {r2:.3f}")          # Variance explained
Output
MAE: 190.00 units
MSE: 1250000.00
RMSE: 1118.03 units
R²: 0.987
Production Trap:
Never report MSE alone to business teams. They can't interpret squared units. Always pair it with MAE or RMSE for actual decision-making.
Key Takeaway
Use MAE for interpretability, MSE for catching outliers, and R² for explaining variance — but always validate on real-world distributions.

Confusion Matrix: The First Thing You Look At After Training

Before you calculate a single metric, look at the confusion matrix. It's a 2x2 grid that tells you exactly where your model fails. True positives, true negatives, false positives, false negatives. No averaging. No hiding. When your fraud model shows 99% accuracy but the confusion matrix reveals 500 false negatives on the fraud class, you know exactly what's broken. The matrix is your ground truth. Use it to calculate precision, recall, and F1 manually at first. It forces you to understand the cost of each error type. In credit risk, false negatives cost you loan defaults. In spam detection, false positives cost you angry users. The confusion matrix makes these trade-offs visible. Production monitoring tip: track the raw counts in your confusion matrix over time. If your false positive rate creeps up from 2% to 5% over two weeks, you'll catch concept drift before it burns you. Don't let automated metrics blind you. Start with the matrix.

confusion_matrix_check.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// io.thecodeforge
from sklearn.metrics import confusion_matrix, classification_report
import numpy as np

y_true = np.array([1, 0, 1, 1, 0, 1, 0, 0, 1, 0])
y_pred = np.array([1, 0, 0, 1, 0, 1, 1, 0, 0, 0])

cm = confusion_matrix(y_true, y_pred)
print("Confusion Matrix:")
print(f"TN={cm[0,0]} FP={cm[0,1]}")
print(f"FN={cm[1,0]} TP={cm[1,1]}")

# Manual calculation - understand the math
tn, fp, fn, tp = cm.ravel()
precision = tp / (tp + fp) if (tp + fp) > 0 else 0
recall = tp / (tp + fn) if (tp + fn) > 0 else 0
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0

print(f"\nPrecision: {precision:.2f}")
print(f"Recall: {recall:.2f}")
print(f"F1: {f1:.2f}")
Output
Confusion Matrix:
TN=3 FP=1
FN=2 TP=4
Precision: 0.80
Recall: 0.67
F1: 0.73
Production Trap:
Don't rely on classification_report() alone. Extract raw confusion matrix values and log them. A drift in TN/FP ratio signals data distribution shift before accuracy drops.
Key Takeaway
Always inspect the confusion matrix first. It reveals the cost of each error type and catches silent model degradation in production.
● Production incidentPOST-MORTEMseverity: high

The 99% Accurate Fraud Detector That Missed All Fraud

Symptom
Model reported 99% accuracy on the test set. In production, fraud alerts dropped to near zero, but chargebacks spiked.
Assumption
High accuracy means the model is performing well. Accuracy is a safe default metric.
Root cause
The dataset had 99.5% legitimate transactions and 0.5% fraud. The model learned to predict 'legitimate' for every input — 99.5% accuracy but zero recall (TPR). Precision was undefined (no positive predictions). The team never looked at recall or a confusion matrix.
Fix
Switch to F1-score as the primary evaluation metric. Add a minimum recall threshold (e.g., 80%) to the model selection criteria. Implement class weighting or resampling to handle imbalance. Re-train with a focus on the minority class.
Key lesson
  • Never rely on accuracy alone for imbalanced datasets — check recall and precision.
  • Always inspect the confusion matrix before signing off a model.
  • Define business success metrics (e.g., fraud caught) and map them to model metrics (recall).
Production debug guideWhen your model's metrics start dropping, follow this symptom-action guide6 entries
Symptom · 01
Overall accuracy drops by 5% but no single metric triggers alarm
Fix
Pull the confusion matrix from the last week. Compare TP, FP, FN, TN rates against the baseline. Check if the drop is uniform or class-specific.
Symptom · 02
Precision stays high but recall plummets
Fix
Model is becoming conservative — it's predicting fewer positives. Check for feature drift, threshold shift, or data distribution change. Recompute optimal threshold using a validation set.
Symptom · 03
AUC-ROC drops while accuracy stays same
Fix
AUC-ROC measures ranking quality. A drop means the model's confidence scores are misordered. Run a probability calibration check (e.g., reliability diagram). Retrain if needed.
Symptom · 04
F1 score oscillates across daily batches
Fix
Inconsistent data quality. Implement data schema validation and distribution monitoring for features used by the model. Flag batches where feature distributions differ from training.
Symptom · 05
PR-AUC drops significantly but AUC-ROC is stable
Fix
PR-AUC is sensitive to minority class performance. AUC-ROC may hide degradation on rare events. Investigate recall drop on the positive class. Rebalance or retrain with cost-sensitive learning.
Symptom · 06
Macro F1 drops while weighted F1 stays high
Fix
Macro F1 treats all classes equally. A drop suggests the minority classes are degrading. Check per-class precision and recall. Retrain with class weights or oversample rare classes.
★ Quick Debug Cheat Sheet: Model Metric DriftUse these commands to diagnose metric drift before it hits your users.
Accuracy looks good but business is unhappy
Immediate action
Generate confusion matrix on production data.
Commands
from io_thecodeforge.metrics import confusion_matrix; confusion_matrix(y_true, y_pred)
from io_thecodeforge.report import classification_report; print(classification_report(y_true, y_pred))
Fix now
Evaluate recall and precision for each class. If recall on minority class < 70%, schedule a retrain with class weights.
Precision/Recall trade-off changed suddenly+
Immediate action
Compare model scores distribution vs training set.
Commands
from io_thecodeforge.stats import ks_statistic; ks_statistic(train_scores, prod_scores)
from io_thecodeforge.calibration import reliability_diagram; plot_reliability(y_true, y_prob)
Fix now
If KS > 0.15, retrain on recent data. If calibration drift, apply isotonic regression.
AUC-ROC dropped > 0.05 since last deploy+
Immediate action
Check for label leakage or feature staleness.
Commands
from io_thecodeforge.drift import feature_drift_report; report = feature_drift_report(reference, production)
from io_thecodeforge.evaluation import auc_roc; auc_roc(y_true, y_prob, multi_class='ovr')
Fix now
Identify top drifting features. Retrain or rollback to previous model version.
Macro F1 significantly lower than weighted F1+
Immediate action
Examine per-class precision and recall. Classes with few samples may be failing.
Commands
from io_thecodeforge.metrics import classification_report; print(classification_report(y_true, y_pred))
from io_thecodeforge.evaluation import confusion_matrix; print(confusion_matrix(y_true, y_pred))
Fix now
Oversample or weight underrepresented classes. Consider ignoring classes with <10 samples in evaluation.
When to Use Which Metric
MetricBest Use CasePitfall
AccuracyBalanced classes, equal error costMisleading on imbalanced data
PrecisionMinimising false positives (e.g., spam filter)Ignores missed positives
RecallMinimising false negatives (e.g., disease screening)Can suffer from low precision
F1 ScoreBalanced trade-off, default for imbalancedMay hide extreme precision-recall imbalance
AUC-ROCComparing classifier ranking abilityOverestimates on imbalanced data
PR-AUCImbalanced datasets, minority class focusLess interpretable than F1
Macro F1Multi-class, equal weight to all classesVolatile for rare classes
Weighted F1Multi-class, account for class frequencyCan hide minority class failures
Log Loss (Cross-Entropy)When you need calibrated probabilitiesHard to interpret without baseline; sensitive to extreme predictions

Key takeaways

1
The confusion matrix is the single most informative output
master it first.
2
Accuracy is dangerous on imbalanced data; always pair it with precision and recall.
3
Precision and recall are always a trade-off
choose based on false positive vs false negative costs.
4
F1 is a good balance but can hide extreme trade-offs
inspect components.
5
AUC-ROC measures ranking ability, not deployment performance
tune threshold separately.
6
PR-AUC is the honest metric for imbalanced minority classes.
7
Cross-validation prevents lucky test splits
always report mean ± std across folds.
8
Business value, not metric value, should drive model selection
build a cost matrix.

Common mistakes to avoid

3 patterns
×

Using accuracy as the only metric on imbalanced data

Symptom
Model reports high accuracy but fails to detect the minority class completely. In production, business metric (e.g., fraud caught) is near zero.
Fix
Always compute precision, recall, and F1 for the minority class. Use a confusion matrix to visualise errors. If business cares about minority, set a minimum recall threshold.
×

Tuning the model to maximise F1 without inspecting components

Symptom
F1 looks good but either precision or recall is very low. Model is useless for the actual business need.
Fix
After hyperparameter tuning, always print classification report. If one class dominates F1, consider per-class F1 or use macro/weighted averages.
×

Setting threshold at 0.5 without validation

Symptom
Model performs poorly in production because the optimal threshold is far from 0.5. Missed fraud or too many false alarms.
Fix
Always tune threshold using a cost matrix on a validation set. Revisit quarterly.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
Explain the difference between accuracy, precision, and recall. When wou...
Q02SENIOR
Why is AUC-ROC not suitable for highly imbalanced datasets? What metric ...
Q03SENIOR
How would you choose the optimal decision threshold for a binary classif...
Q04SENIOR
What is the difference between macro F1, micro F1, and weighted F1? When...
Q01 of 04JUNIOR

Explain the difference between accuracy, precision, and recall. When would you choose recall over precision?

ANSWER
Accuracy is the fraction of correct predictions. Precision is TP/(TP+FP) — how many predicted positives are correct. Recall is TP/(TP+FN) — how many actual positives are caught. Choose recall when false negatives are costly (e.g., cancer screening). Choose precision when false positives are costly (e.g., spam filter for important emails). Always inspect both together.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
Can accuracy ever be a reliable metric?
02
What should I do if my model has high AUC-ROC but low recall?
03
How often should I re-evaluate my model's decision threshold?
04
Is macro F1 always better than weighted F1?
N
Naren Founder & Principal Engineer

20+ years shipping production ML systems and the infrastructure behind them. Notes here come from systems that actually shipped.

Follow
Verified
production tested
May 24, 2026
last updated
1,554
articles · all by Naren
🔥

That's MLOps. Mark it forged?

15 min read · try the examples if you haven't

Previous
Model Deployment with Flask
3 / 14 · MLOps
Next
A/B Testing in ML