When the Outcome Is Yes/No
Linear regression predicts a number. But many of the questions worth modeling are binary: does the customer churn, does the patient recover, does the email get clicked. Fitting a straight line to a 0/1 outcome breaks immediately - the line happily predicts probabilities of −0.3 or 1.4, which are nonsense.
Logistic regression fixes this by modeling the probability of the outcome through the log-odds (logit) transform: log(p / (1 − p)) = intercept + slope × x. The log-odds scale runs the whole number line, so a linear equation fits naturally there - and mapping back squeezes every prediction into (0, 1) along the familiar S-shaped curve. The price of the trick: coefficients live on the log-odds scale, and the whole game of reading a logistic regression is translating them back into something humans understand.
Fitting: glm() with family = binomial
glm() (generalized linear model) is lm()'s big sibling; family = binomial selects logistic regression. In mtcars, am records transmission type (1 = manual, 0 = automatic) - do fuel-efficient cars tend to be manual?
Two things before reading the output. First, family = binomial is not optional - omit it and glm() silently fits ordinary least squares. Second, the outcome must be binary: 0/1, logical, or a two-level factor (R models the probability of the second level).
Now the summary, block by block:
- Coefficients - the
mpgEstimate is about 0.31, and it is a log-odds slope: each extra mpg adds 0.31 to the log-odds of being manual. Positive means "raises the probability," negative means "lowers" - beyond the sign, nobody's intuition works on this scale, which is why the next section exists. - z value and Pr(>|z|) - same logic as regression's t-tests (Estimate ÷ Std. Error, then a p-value for "could this be zero?"), just using a normal approximation - hence z instead of t. Here p ≈ 0.011: the association between mpg and transmission type is unlikely to be noise.
- Null deviance vs Residual deviance - deviance is the glm world's badness-of-fit (smaller = better). Null deviance (43.2 on 31 df) is the intercept-only model; residual deviance (29.7 on 30 df) is yours. The drop of about 13.6 for one predictor's worth of df is the glm analogue of "R-squared went up."
- AIC - a model-comparison score balancing fit against complexity; lower wins. Meaningless alone, useful between candidate models on the same data.
From Log-Odds to Odds Ratios: exp(coef())
Exponentiating moves coefficients from the additive log-odds scale to the multiplicative odds scale:
exp(0.307) ≈ 1.36, and here is the honest sentence pattern to memorize: "each extra mpg multiplies the odds of a manual transmission by about 1.36." An odds ratio above 1 raises the odds, below 1 lowers them, exactly 1 is no effect - which is why the confidence interval verdict for odds ratios is "does the interval exclude 1?" (not zero; zero was the boundary back on the log-odds scale).
Mind the language: odds are not probabilities. Odds = p / (1 − p), so probability 0.75 is odds of 3. Multiplying odds by 1.36 is not the same as multiplying probability by 1.36 - and when the outcome is common, the gap is large. An odds ratio of 2 for a rare outcome behaves like "roughly double the risk"; for an outcome running at 50%, it emphatically does not. Never report an odds ratio with risk-ratio wording ("1.36 times as likely") unless the outcome is rare.
Predicted Probabilities: the type = "response" Gotcha
The single most common logistic-regression bug in the wild:
The first call returns the default type = "link" - predictions on the log-odds scale, negative values and all. The second returns actual probabilities. If your "probabilities" ever come out negative or above 1, this is why. Run the block: a 15-mpg car has essentially no chance of being manual, a 30-mpg car is very likely manual, and the S-curve bends through the middle.
Classification: Thresholding and the Confusion Table
Probabilities become predicted classes by choosing a cutoff - 0.5 being the default choice - and the honest scorecard is a table of predicted vs actual:
The diagonal cells are correct calls; the two off-diagonal cells are the two different mistakes (predicting manual for an automatic, and the reverse). Overall accuracy alone can flatter a model badly - if 95% of customers don't churn, "predict nobody churns" scores 95% while catching zero churners - so always look at both error types. And 0.5 is a convention, not a law: when the two mistakes have different costs, move the threshold accordingly.
One honesty caveat: this table scores the model on the same data it was fit on, which flatters it. Real evaluation holds out data the model never saw.
Multiple Predictors
Exactly like lm() - add terms with +, and every interpretation gains the qualifier "holding the others constant":
Each exponentiated coefficient is now the odds multiplier for a one-unit increase in that predictor among cars alike on the other predictors. The machinery scales, but so do the caveats from linear regression: correlated predictors reshuffle each other's coefficients.
Cautions
- Complete separation. If a predictor splits the outcome perfectly (every car above some mpg is manual, every one below is automatic), the maximum-likelihood coefficient wants to be infinite. R warns -
glm.fit: fitted probabilities numerically 0 or 1 occurred- and reports huge coefficients with absurd standard errors. Don't ship those numbers; simplify the model, get more data, or use a penalized method (thebrglm2orlogistfpackages). - Enough events. The binding constraint is the count of the rarer outcome, not total rows. An old rule of thumb wants on the order of 10-15 events per predictor; the 32-car examples here are for teaching the mechanics, not a template for publishable sample sizes.
- Odds ratios are not risk ratios when the outcome is common - covered above, repeated because reviewers will catch it even if you don't.
What You Take Away
- Binary outcome →
glm(y ~ x, data = df, family = binomial); never forget thefamily. - Raw coefficients are log-odds;
exp(coef(fit))gives odds ratios, and the null value for their intervals is 1. - The sentence pattern: "each one-unit increase in x multiplies the odds of the outcome by exp(b)."
predict(..., type = "response")for probabilities - the default returns log-odds, the number-one confusion.- Classify with a threshold and judge with a confusion table; accuracy alone can lie.
- Watch for separation warnings, count your events, and don't dress odds ratios up as risk ratios.
Next up: the machinery behind every interval you've seen so far - confidence intervals with t.test(), confint() and prop.test().
Frequently Asked Questions
How do you run a logistic regression in R?
With glm() and family = binomial: fit <- glm(am ~ mpg, data = mtcars, family = binomial), then summary(fit). The outcome must be binary - 0/1, TRUE/FALSE, or a two-level factor. Forgetting family = binomial silently fits ordinary linear regression instead.
How do you interpret glm coefficients in R?
Raw coefficients are on the log-odds scale, which nobody thinks in. Exponentiate them - exp(coef(fit)) - to get odds ratios: a value of 1.36 for a predictor means each one-unit increase multiplies the odds of the outcome by about 1.36. Values above 1 raise the odds, below 1 lower them, exactly 1 means no effect.
How do you get predicted probabilities from glm in R?
Use predict(fit, newdata, type = "response"). This is the number-one gotcha: the default type = "link" returns log-odds, not probabilities - so if your "probabilities" are negative or above 1, you forgot type = "response".
What is the difference between odds and probability?
Probability is successes over all trials; odds are successes over failures. A probability of 0.75 is odds of 3 (three successes per failure). Logistic regression's odds ratios multiply odds, not probabilities - and when the outcome is common, an odds ratio can be much larger than the corresponding risk ratio, so don't present one as the other.