Deciding whether to believe a model
Anyone can train a surrogate. The useful question is whether you should believe it, and that is a question about evaluation, not about architecture.
The same question runs through my own reduced-order work on particle breakage. Fitting the model was never the hard part. Knowing the conditions under which its prediction can be trusted, and being able to say where it stops, was.
That is the same discipline as verifying a solver. A residual tells you an iteration stopped moving; it does not tell you it stopped at the right answer. An accuracy score tells you a classifier agrees with the majority class; it does not tell you the model is useful. In both cases the number that is easy to compute is not the number that decides anything.
Two small projects where I worked that through on problems where the ground truth is available, so the reasoning is checkable.
The model that wins on F1 is not the one to deploy
SMS spam detection: 5,572 messages, 13.4% spam. Classical TF–IDF baselines against a fine-tuned DistilBERT, same split, same protocol.
| Model | Precision | Recall | F1 | Accuracy |
|---|---|---|---|---|
| TF–IDF + logistic regression | 1.00 | 0.83 | 0.91 | 0.98 |
| TF–IDF + naive Bayes | 0.98 | 0.85 | 0.91 | 0.98 |
| Logistic regression, threshold tuned | 0.97 | 0.89 | 0.93 | 0.98 |
| DistilBERT | 0.98 | 0.97 | 0.97 | 0.99 |
Every model scores 0.98–0.99 accuracy while recall ranges from 0.83 to 0.97, which is the first thing worth noticing: at 13% positives, accuracy separates nothing. A model that predicts "not spam" every time scores 0.866.
DistilBERT wins on recall and F1, and the margin is real, 0.83 to 0.97 is about 21 more spam messages caught out of 149. But translated into messages on the test set:
| Spam caught (of 149) | Legitimate messages misfiled (of 966) | |
|---|---|---|
| Logistic regression | 124 | 0 |
| DistilBERT | ~145 | ~3 |
Logistic regression is at precision 1.00, it never touches a real message. DistilBERT catches 21 more spam messages and introduces an error class the baseline does not have at all.
Those two mistakes are not worth the same. A spam message in the inbox is deleted in a second. A real message silently moved to a spam folder can be missed entirely: a verification code, an appointment, a person. If the cost ratio is anything like ten to one, the baseline's error profile is the better one despite losing on every headline metric.
F1 weights precision and recall equally. That is an assumption about the application, and here it is the wrong one. The metric has to come from the cost of each mistake before the model comparison means anything.
Model ranking depends on the operating point
Customer churn on the IBM Telco dataset, ~27% churn. Logistic regression, a decision tree and a random forest through one preprocessing pipeline, with the transformer fitted inside cross-validation so the test split does not leak into the fit.
| Model | ROC AUC | F1 (churn) |
|---|---|---|
| Logistic regression | 0.84 | 0.61 |
| Decision tree | 0.83 | 0.61 |
| Random forest | 0.84 | 0.55 |
At the default threshold, logistic regression wins. Similar ROC AUC across all three says they rank churn risk about equally well, so the difference is where each puts its decision boundary, a threshold question rather than a model question. Lowering the threshold from 0.5 to 0.3:
| At threshold 0.3 | Precision | Recall | F1 |
|---|---|---|---|
| Logistic regression | 0.41 | 0.93 | lower than at 0.5 |
| Random forest | 0.52 | 0.78 | 0.63 |
The ranking flips. The random forest looked worse at the default threshold and is better at the operating point a business would actually choose.
Model selection and threshold selection are one decision, not two. Evaluating at 0.5 alone would have picked the wrong model, and 0.5 is a default, not a choice anyone made.
The error analysis is the part I would carry into a surrogate. The random forest's mistakes are not scattered: they concentrate in month-to-month contracts, at moderate-to-high tenure rather than among new customers, at an above-average monthly charge. That is a coherent segment whose churn driver is not in the dataset. More model capacity will not fix it; more features would. Knowing which of those two you are looking at is the whole game.
What this has to do with solvers
A manufactured solution lets you measure a solver's error instead of inferring it from a residual, and that is why my Poisson study uses one: the observed order of accuracy comes out at 2.06 against a formal 2, which is checkable rather than asserted. Held-out conditions and conservation checks do the same job for a surrogate.
The failure mode I care about is the quiet one. A solver that diverges has told you something. A solver that converges to a plausible wrong answer has not, and neither has a surrogate that interpolates beautifully inside its training envelope and is confidently wrong outside it. Both need an external reference and someone willing to go looking.
The code
-
text-classification
TF–IDF baselines against DistilBERT on SMS spam. ROC and precision–recall curves, threshold tuning, and the error analysis behind the table above.
-
churn-prediction
End to end in one notebook: EDA, preprocessing pipelines, three models, feature importance cross-checked across all three, threshold tuning against business cost, and error analysis.
-
Membrane-permeability-using-ML
Predicting whether a drug-like molecule crosses a lipid membrane from its SMILES string alone. A four-person course project; I built the RDKit feature generation (200 molecular descriptors and 1024-bit Morgan fingerprints), and the cross-validated regularisation search and learning-curve diagnostics for the Lasso model.