ConvergenceWarning: lbfgs failed to converge (scikit-learn)
The optimiser hit its iteration limit before settling. Scale your features first — that fixes most cases — and raise max_iter second.
Updated
The error
ConvergenceWarning: lbfgs failed to converge (status=1):
STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.
Increase the number of iterations (max_iter) or scale the data as shown in:
https://scikit-learn.org/stable/modules/preprocessing.htmlWhat it means
This is a warning, not an error — you still have a fitted model. lbfgs is the optimisation algorithm behind LogisticRegression and friends: it walks downhill on the loss function until the steps become tiny. Here it ran out of its iteration budget (default 100) while the steps were still large. The coefficients you got are wherever it happened to stop, which may or may not be good.
Why it happens
The message suggests raising max_iter, but that treats the symptom. The usual disease is unscaled features. When one column ranges 0-1 and another 0-500,000, the loss surface becomes a long narrow valley. The optimiser zigzags along it and 100 iterations are nowhere near enough. Scaled features make the valley round, and the same problem converges in a handful of steps.
How to fix it
1. Scale the features — inside a pipeline. This is the real fix in most cases.
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
model = make_pipeline(StandardScaler(), LogisticRegression())
model.fit(X_train, y_train)StandardScaler shifts each feature to mean 0 and spread 1. The pipeline guarantees the scaler is fitted on training data only and applied identically at prediction time.
2. Raise max_iter if the warning persists.
LogisticRegression(max_iter=1000)Harmless: iterating longer costs a little time, nothing else. If 1000 is still not enough on scaled data, something else is off — often near-duplicate columns or perfectly separable data.
3. Consider a different solver for unusual shapes of data.
LogisticRegression(solver="liblinear") # small datasets
LogisticRegression(solver="saga") # very large or sparse datasets4. Do not silence the warning without fixing it. Suppressing it leaves you with a half-optimised model that quietly underperforms.
How to prevent it
Make make_pipeline(StandardScaler(), <linear model>) your default habit for anything with coefficients — logistic and linear regression, SVMs, neural networks. Tree models (random forests, gradient boosting) do not need scaling, which is one reason they are so forgiving.
Related errors
- NotFittedError: instance is not fitted yet
- Loss is NaN during training — the deep-learning cousin of optimisation gone wrong
- ValueError: could not convert string to float