Simple linear regression models the relationship:
\[ Y = \beta_0 + \beta_1X + \epsilon \]
2025-10-19
Simple linear regression models the relationship:
\[ Y = \beta_0 + \beta_1X + \epsilon \]
For this demonstration, we’ll use the built-in trees dataset in R.
It contains measurements of the Girth, Height, and Volume of 31 Black Cherry trees.
head(trees)
## Girth Height Volume ## 1 8.3 70 10.3 ## 2 8.6 65 10.3 ## 3 8.8 63 10.2 ## 4 10.5 72 16.4 ## 5 10.7 81 18.8 ## 6 10.8 83 19.7
We’ll start by examining the relationship between Girth and Volume.
library(ggplot2)
p1 <- ggplot(trees, aes(x = Girth, y = Volume)) +
geom_point(color = "#8C1D40", size = 3) +
ggtitle("Tree Volume vs. Girth") +
xlab("Girth (in inches)") +
ylab("Volume (in cubic feet)") +
theme_minimal()
p1
The regression model estimates a line that best fits the data.
p2 <- p1 + geom_smooth(method = "lm", se = FALSE, color = "darkblue") p2
## `geom_smooth()` using formula = 'y ~ x'
\[ \text{Volume} = \beta_0 + \beta_1(\text{Girth}) + \epsilon \]
We can estimate model parameters analytically using lm().
model <- lm(Volume ~ Girth, data = trees) summary(model)
## ## Call: ## lm(formula = Volume ~ Girth, data = trees) ## ## Residuals: ## Min 1Q Median 3Q Max ## -8.065 -3.107 0.152 3.495 9.587 ## ## Coefficients: ## Estimate Std. Error t value Pr(>|t|) ## (Intercept) -36.9435 3.3651 -10.98 7.62e-12 *** ## Girth 5.0659 0.2474 20.48 < 2e-16 *** ## --- ## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 ## ## Residual standard error: 4.252 on 29 degrees of freedom ## Multiple R-squared: 0.9353, Adjusted R-squared: 0.9331 ## F-statistic: 419.4 on 1 and 29 DF, p-value: < 2.2e-16
The equation from our model is approximately:
\[ \widehat{Volume} = -36.94 + 5.07(Girth) \]
This means each unit increase in Girth increases Volume by about 5 cubic feet.
Make the regression result interactive with plotly.
library(plotly)
## ## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2': ## ## last_plot
## The following object is masked from 'package:stats': ## ## filter
## The following object is masked from 'package:graphics': ## ## layout
fig <- plot_ly(trees, x = ~Girth, y = ~Volume, type = "scatter", mode = "markers",
marker = list(color = 'rgba(165,0,52,0.7)', size = 9)) %>%
add_lines(x = ~Girth, y = fitted(model), name = "Fitted Line",
line = list(color = 'blue', width = 3)) %>%
layout(title = "Interactive Regression Line",
xaxis = list(title = "Girth (inches)"),
yaxis = list(title = "Volume (cubic feet)"))
fig
## A marker object has been specified, but markers is not in the mode ## Adding markers to the mode...
To find the slope and intercept:
\[ \beta_1 = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})} {\sum (x_i - \bar{x})^2} \]
\[ \beta_0 = \bar{y} - \beta_1 \bar{x} \]
These equations minimize the sum of squared residuals (SSR).
We can predict tree volume for new Girth values:
new_data <- data.frame(Girth = c(10, 15, 20)) predict(model, new_data)
## 1 2 3 ## 13.71511 39.04439 64.37367
This shows a 3D simulated surface using synthetic data.
set.seed(123)
x <- seq(5, 20, by=0.5)
y <- seq(50, 100, by=2)
z <- outer(x, y, function(x, y) sin(x/2) + log(y))
plot_ly(x = ~x, y = ~y, z = ~z, type = "surface") %>%
layout(scene = list(xaxis = list(title="Girth"),
yaxis = list(title="Height"),
zaxis = list(title="Predicted Volume")))