Training logs are full of ConvergenceWarning: The max_iter was reached which means the coef_ did not converge (sometimes hundreds of copies from a tuning loop). The code
"works" — a model comes out and predicts — but its scores sit at or near the dumb
baseline, coefficients look small and strange, and results shift between runs and
machines.
LogisticRegression (and other iterative solvers: SAG/SAGA, sometimes lbfgs) trained on
raw, unscaled features — typically tables mixing counts with rupee amounts in the
hundreds or thousands. Warnings scroll past unread in notebooks and CI logs, or worse,
someone has added warnings.filterwarnings("ignore") at the top of the script. Linked
module: 1.3 (Linear & logistic regression).
Convergence means the solver's downhill walk on the loss curve (module 0.7's picture)
reached the bottom — the coefficients stopped changing. This warning says the opposite:
the step budget (max_iter, default 100) ran out mid-descent, so coef_ is whatever
the walk held when the whistle blew. The model is half-trained, not broken — which is
what makes it dangerous: it still predicts, plausibly but poorly. Unscaled features are
the usual cause: a column swinging 100–900 next to one swinging 1–15 stretches the loss
valley into a long thin trench that iterative solvers crawl along. Confirm in three
steps: (1) compare test accuracy against the majority-class baseline — a half-trained
model often lands exactly there; (2) print model.n_iter_ — it will equal max_iter;
(3) refit with scaled features and watch n_iter_ collapse (100+ down to single digits)
while the score jumps.
Scale the features — make_pipeline(StandardScaler(), LogisticRegression()) — which
fixes the cause and usually converges in a handful of iterations. If the warning
persists (very wide data, strong regularisation settings), raise max_iter to give the
solver room, and prefer the default lbfgs solver unless you specifically need another.
Never fix it by silencing warnings: the message is telling you the coefficients are
provisional. After the fix, re-read any coefficient story produced by the half-trained
model — it was noise.
Put scaling in the pipeline from the first fit, not as an afterthought — it also makes
coefficients comparable (WR-061's fix, same habit). Treat ConvergenceWarning as a
build-stopper in CI: fail the job on it rather than letting it spam. Log n_iter_
alongside scores in every training run. When copying solver settings from a blog
snippet, know what each one is for — solver="saga" exists for L1 penalties and big
data, and it is the slowest crawler on unscaled features.
Q: "Your logistic regression trains without errors but performs no better than
predicting the majority class. Where do you look?" Strong answer: check the warnings,
explain what convergence means in one sentence (the downhill walk finished), connect
unscaled features to the stretched loss valley, and give the two-part fix — scale in a
pipeline first, raise max_iter second. Quoting n_iter_ as the confirming evidence
separates candidates who have debugged this from those who memorised it.