Quick summary
Summarize this blog with AI
Introduction
The warning glm.fit: algorithm did not converge says the fitting iteration did not meet its convergence criterion. It does not identify the cause. This lesson focuses on binomial logistic regression and separates an artificially small iteration budget from complete separation, where ordinary maximum-likelihood coefficients have no finite solution.
Tested with R 4.5.1 and detectseparation 0.4.0. Run the code blocks in order. Install the named packages before starting; inputs are supplied below.
Validate the data actually used by the model
Begin with a small overlapping binary-outcome fixture. Missing observations are rejected explicitly rather than silently changing the analysis population.
d <- data.frame(x = rep(-2:2, each = 4),
y = c(0,0,0,1, 0,0,1,0, 0,1,0,1, 1,1,0,1, 1,1,1,0))
stopifnot(nrow(d) > 0L, all(d$y %in% c(0, 1)),
all(is.finite(d$x)), length(unique(d$y)) == 2L)
frame <- model.frame(y ~ x, data = d, na.action = na.fail)
X <- model.matrix(y ~ x, frame)
stopifnot(qr(X)$rank == ncol(X))
print(table(d$x, d$y))
Inspect the family/link, response coding, weights and offsets as well as predictors. These checks are specific to this unweighted binary example. A rank-deficient design and separation are different problems.
Reproduce a genuine iteration-limit warning
One iteration is deliberately insufficient. The handler records the warning so the demonstration can continue; it does not make the failed fit usable.
messages <- character(0)
short <- withCallingHandlers(
glm(y ~ x, data = d, family = binomial(), control = glm.control(maxit = 1)),
warning = function(w) { messages <<- c(messages, conditionMessage(w)); invokeRestart("muffleWarning") })
stopifnot(!short$converged, any(grepl("algorithm did not converge", messages, fixed = TRUE)))
fit <- glm(y ~ x, data = d, family = binomial(), na.action = na.fail,
control = glm.control(maxit = 25, epsilon = 1e-8))
stopifnot(fit$converged, all(is.finite(coef(fit))))
print(round(coef(fit), 6)) # intercept 0; x 0.673996
stopifnot(abs(coef(fit)[[2]] - 0.673996) < 1e-6)
Here the larger budget solves the demonstrated problem. R’s glm.control uses a relative deviance-change criterion. A smaller epsilon is a stricter tolerance, not a general convergence cure. A converged fit still needs scientific and predictive validation.
Detect complete separation rather than deleting observations
In this second fixture, x perfectly separates zeros from ones. Increasing the slope always improves the likelihood toward its supremum; a finite maximum-likelihood slope does not exist.
separated <- data.frame(x = c(-3, -2, -1, 1, 2, 3), y = c(0, 0, 0, 1, 1, 1))
limited <- suppressWarnings(glm(y ~ x, data = separated, family = binomial(),
control = glm.control(maxit = 10)))
stopifnot(!limited$converged)
diagnostic <- glm(y ~ x, data = separated, family = binomial(),
method = detectseparation::detect_separation)
print(coef(diagnostic)) # intercept -Inf; x Inf for this diagnostic
stopifnot(any(is.infinite(coef(diagnostic))))
The diagnostic’s infinite entries identify infinite maximum-likelihood components; they are not fitted effect estimates. detectseparation documents this convention. Numerical convergence alone can be misleading under separation, so inspect the data and separation diagnostic even if more iterations remove a warning.
Choose a remedy for the diagnosed cause
Use a deliberate failure for missing inputs, and preserve an audit of which records a model uses.
bad <- d; bad$x[1] <- NA_real_
stopifnot(inherits(tryCatch(glm(y ~ x, data = bad, family = binomial(),
na.action = na.fail), error = identity), "error"))
stopifnot(nobs(fit) == nrow(d))
stopifnot(inherits(tryCatch(glm(y ~ x, data = d[FALSE, ], family = binomial()),
error = identity), "error"))
For separation, investigate coding or leakage and consider a justified bias-reduced or penalized logistic model, reporting the changed estimator. Do not delete valid rows, run stepwise selection, or change a link merely to silence the warning. For poor scaling, rescale meaningful predictors and check equivalence; for a small budget, compare iteration progress and stable estimates. Multiple imputation requires fitting and pooling across imputations, not treating the first completed dataset as the complete procedure.