Linear Regression
Prerequisites: Descriptive statistics, Data visualization with ggplot2
Linear regression models how an outcome changes with one or more predictors. It's the workhorse of statistics — and R was built for it.
We'll use mtcars, a dataset included with R (fuel economy and design
data for 32 cars from 1974).
A simple model
model <- lm(mpg ~ wt, data = mtcars)
coef(model)
(Intercept) wt
37.285126 -5.344472
mpg ~ wtis a formula: "modelmpg(miles per gallon) as a function ofwt(weight, in 1000s of pounds)".- The slope for
wtis about -5.34: each extra 1,000 pounds is associated with about 5.3 fewer miles per gallon, on average. - The intercept (37.3) is the predicted mpg at zero weight — not meaningful here, but needed to place the line.
How good is the model?
model <- lm(mpg ~ wt, data = mtcars)
s <- summary(model)
round(s$r.squared, 3)
round(s$coefficients, 4)
[1] 0.753
Estimate Std. Error t value Pr(>|t|)
(Intercept) 37.2851 1.8776 19.8576 0
wt -5.3445 0.5591 -9.5590 0
- R² (0.753) is the proportion of variation in mpg explained by weight — about 75%.
- The standard error measures uncertainty in each estimate; the
p-value (
Pr(>|t|), rounded to 0 here) tests whether the true slope could plausibly be zero. A tiny p-value suggests a real relationship — but says nothing about causation or practical importance.
Run summary(model) on its own to see the full report, including
residuals and an overall F-test.
Several predictors
model2 <- lm(mpg ~ wt + hp + factor(cyl), data = mtcars)
round(coef(model2), 3)
round(summary(model2)$adj.r.squared, 3)
(Intercept) wt hp factor(cyl)6 factor(cyl)8
35.846 -3.181 -0.023 -3.359 -3.186
[1] 0.836
- Each slope is now the effect of that variable holding the others constant.
factor(cyl)treats cylinder count as categories: the coefficients compare 6- and 8-cylinder cars with 4-cylinder cars.- Adjusted R² penalizes extra predictors, so it's the fairer way to compare models of different sizes.
Predictions and checking assumptions
model <- lm(mpg ~ wt, data = mtcars)
new_cars <- data.frame(wt = c(2.5, 3.5))
round(predict(model, new_cars, interval = "confidence"), 2)
fit lwr upr
1 23.92 22.55 25.30
2 18.58 17.43 19.73
Linear regression assumes a roughly straight-line relationship and
evenly spread, independent errors. Check with plot(model), which draws
diagnostic plots, and always plot the raw data first — a single outlier
or a curved pattern can make a model misleading. The broom package's
tidy() and glance() turn model results into tibbles, which is handy
for comparing many models.
Common mistakes
- Interpreting a regression slope as a causal effect. Observational data shows association; causal claims need careful design.
- Extrapolating — predicting far outside the range of the data used to fit the model.