Skip to content
AgileLogics
8 min read

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 ~ wt is a formula: "model mpg (miles per gallon) as a function of wt (weight, in 1000s of pounds)".
  • The slope for wt is 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.