---
title: "Multiple Linear Regression - Model Building"
subtitle: "Notes and in-class exercises"
format: 
  html:
    embed-resources: true
    toc: true
---



You can download the .qmd file for this activity [here](../activity_templates/13+14-mlr-model-building.qmd) and open in R-studio. The rendered version is posted in the [course website](https://mutasim221b.github.io/Mac-STAT-155-Fall-25/) (Activities tab). I often experiment with the class activities (and see it in live!) and make updates, but I always post the final version before class starts. To be sure you have the most up-to-date copy, please download it once you’ve settled in before class begins.





```{r setup}
#| include: false
knitr::opts_chunk$set(
  collapse = TRUE, 
  warning = FALSE,
  message = FALSE,
  error = TRUE,
  fig.height = 2.75, 
  fig.width = 4.25,
  fig.env = 'figure',
  fig.pos = 'h',
  fig.align = 'center')
```



# Notes on Model Building 

## Learning goals

By the end of this lesson, you should be able to:

- Explain when variables are redundant or multicollinear.
- Relate redundancy and multicollinearity to coefficient estimates and $R^2$.
- Explain why adjusted $R^2$ is preferable to multiple $R^2$ when comparing models with different numbers of predictors.

## Readings and videos

Today is a day to discover ideas, so no readings or videos to go through before class, but if you want to see today's ideas presented in a different way, you can take a look at the following after class:

- Reading: Section 3.9.5 in the [STAT 155 Notes](https://mac-stat.github.io/Stat155Notes/)
- Video: [Redundancy and Multicollinearity](https://voicethread.com/share/15177737/)




**File organization:** Save this file in the "Activities" subfolder of your "STAT155" folder.



# Exercises


Today we'll visit predictive research questions and some considerations when trying to build *strong* models. In particular, we'll consider nuances and limitations to indiscriminately adding more predictors to our model. To explore these ideas, load the following data on penguins:

```{r}
# Load packages & data
library(tidyverse)
data(penguins)
head(penguins)
```

You can find a **codebook** for these data by typing `?penguins` **in your console (not Rmd)**. Our goal throughout will be to build a model of bill lengths (in mm):

![](https://allisonhorst.github.io/palmerpenguins/reference/figures/culmen_depth.png)

(Art by @allison_horst)


To get started, the `flipper_len` variable currently measures flipper length in mm. Let's create and save a *new* variable named `flipper_len_cm` which measures flipper length in cm. NOTE: There are 10mm in a cm.

```{r}
penguins <- penguins %>% 
    mutate(flipper_len_cm = flipper_len / 10)
head(penguins)
```

Run the code chunk below to build a bunch of models that you'll be exploring in the exercises: 

```{r}
penguin_model_1 <- lm(bill_len ~ flipper_len, penguins)
penguin_model_2 <- lm(bill_len ~ flipper_len_cm, penguins)
penguin_model_3 <- lm(bill_len ~ flipper_len + flipper_len_cm, penguins)
penguin_model_4 <- lm(bill_len ~ body_mass, penguins)
penguin_model_5 <- lm(bill_len ~ flipper_len + body_mass, penguins)
```



## Exercise 1: Modeling bill length by flipper length

What can a penguin's flipper (arm) length tell us about their bill length? To answer this question, we'll consider 3 of our models:

model              predictors
------------------ ---------------------------
`penguin_model_1`  `flipper_len`
`penguin_model_2`  `flipper_len_cm`
`penguin_model_3`  `flipper_len + flipper_len_cm`


Plots of the first two models are below:

```{r}
library(ggplot2)
ggplot(penguins, aes(y = bill_len, x = flipper_len)) + 
    geom_point() +
    geom_smooth(method = "lm", se = FALSE)

ggplot(penguins, aes(y = bill_len, x = flipper_len_cm)) + 
    geom_point() +
    geom_smooth(method = "lm", se = FALSE)
```

a. *Before* examining the model summaries, check your intuition. Do you think the `penguin_model_2` R-squared will be less than, equal to, or more than that of `penguin_model_1`? Similarly, how do you think the `penguin_model_3` R-squared will compare to that of `penguin_model_1`?

b. Check your intuition: Examine the R-squared values for the three penguin models and summarize how these compare.

```{r}
summary(penguin_model_1)$r.squared
summary(penguin_model_2)$r.squared
summary(penguin_model_3)$r.squared
```

c. Explain why your observation in part b makes sense. Support your reasoning with a plot of just the 2 *predictors*: `flipper_len` vs `flipper_len`.

```{r}
ggplot(penguins, aes(x = flipper_len, y = flipper_len_cm)) +
    geom_point()
```



d. *OPTIONAL challenge:* In `summary(penguin_model_3)`, the `flipper_len` coefficient is `NA`. Explain why this makes sense. HINT: Thinking about what you learned about controlling for covariates, why wouldn't it make sense to interpret this coefficient? BONUS: For those of you that have taken MATH 236, this has to do with matrices that are not of full rank!



## Exercise 2: Incorporating `body_mass`   

In this exercise you'll consider 3 models of `bill_len`:

model              predictors
------------------ ---------------------------
`penguin_model_1`  `flipper_len`
`penguin_model_4`  `body_mass`
`penguin_model_5`  `flipper_len + body_mass`
 
 
```{r}
summary(penguin_model_1)$r.squared
summary(penguin_model_4)$r.squared
```

a. Which is the better predictor of `bill_len`: `flipper_len` or `body_mass`? Provide some numerical evidence.

b. `penguin_model_5` incorporates both `flipper_len` and `body_mass` as predictors. *Before* examining a model summary, ask your gut: Will the `penguin_model_5` R-squared be close to 0.35, close to 0.43, or greater than 0.6?

c. Check your intuition. Report the `penguin_model_5` R-squared and summarize how this compares to that of `penguin_model_1` and `penguin_model_4`.

```{r}
summary(penguin_model_5)$r.squared
```

d. Explain why your observation in part c makes sense. Support your reasoning with a plot of the 2 *predictors*: `flipper_len` vs `body_mass`.

```{r}
ggplot(penguins, aes(x = flipper_len, y = body_mass)) +
    geom_point()
```



## Exercise 3: Redundancy and Multicollinearity

The exercises above have illustrated special phenomena in multivariate modeling:

- two predictors are **redundant** if they contain the same exact information
- two predictors are **multicollinear** if they are strongly associated (they contain very similar information) but are not completely redundant.

Recall that we examined 5 models:

model              predictors
------------------ ---------------------------
`penguin_model_1`  `flipper_len`
`penguin_model_2`  `flipper_len_cm`
`penguin_model_3`  `flipper_len + flipper_len_cm`
`penguin_model_4`  `body_mass`
`penguin_model_5`  `flipper_len + body_mass`


a. Which model had *redundant* predictors and which predictors were these?
b. Which model had *multicollinear* predictors and which predictors were these?
c. In general, what happens to the R-squared value if we add a *redundant* predictor to a model: will it decrease, stay the same, increase by a small amount, or increase by a significant amount?
d. Similarly, what happens to the R-squared value if we add a *multicollinear* predictor to a model: will it decrease, stay the same, increase by a small amount, or increase by a significant amount?



## Exercise 4: Considerations for strong models

Let's dive deeper into important considerations when building a *strong* model. We'll use a subset of the penguins data for exploring these ideas.

```{r}
# For illustration purposes only, take a sample of 10 penguins.
# We'll discuss this code later in the course!
set.seed(155)
penguins_small <- sample_n(penguins, size = 10) %>%
  mutate(flipper_len = jitter(flipper_len))
```


Consider 3 models of bill length:

```{r}
# A model with one predictor (flipper_len)
poly_mod_1 <- lm(bill_len ~ flipper_len, penguins_small)

# A model with two predictors (flipper_len and flipper_len^2)
poly_mod_2 <- lm(bill_len ~ poly(flipper_len, 2), penguins_small)

# A model with nine predictors (flipper_len, flipper_len^2, ... on up to flipper_len^9)
poly_mod_9 <- lm(bill_len ~ poly(flipper_len, 9), penguins_small)
```

a. Before doing any analysis, which of the three models do you think will be best?
b. Calculate the R-squared values of these 3 models. Which model do you think is best?

```{r}
summary(poly_mod_1)$r.squared
summary(poly_mod_2)$r.squared
summary(poly_mod_9)$r.squared
```

c. Check out plots depicting the relationship estimated by these 3 models. Which model do you think is best?

```{r}
# A plot of model 1
ggplot(penguins_small, aes(y = bill_len, x = flipper_len)) + 
    geom_point() + 
    geom_smooth(method = "lm", se = FALSE)
```

```{r}
# A plot of model 2
ggplot(penguins_small, aes(y = bill_len, x = flipper_len)) + 
    geom_point() + 
    geom_smooth(method = "lm", formula = y ~ poly(x, 2), se = FALSE)
```

```{r}
# A plot of model 9
ggplot(penguins_small, aes(y = bill_len, x = flipper_len)) + 
    geom_point() + 
    geom_smooth(method = "lm", formula = y ~ poly(x, 9), se = FALSE)
```



## Exercise 5: Reflecting on these investigations

a. List 3 of your favorite foods. Now imagine making a dish that combines all of these foods. Do you think it would taste good?
b. Too many good things doesn't make necessarily make a better thing. Model 9 demonstrates that it's always *possible* to get a perfect R-squared of 1, but there are drawbacks to putting more and more predictors into our model. Answer the following about model 9:
    - How easy would it be to interpret this model?
    - Would you say that this model captures the general trend of the relationship between `bill_len` and `flipper_len`?
    - How well do you think this model would generalize to penguins that were not included in the `penguins_small` sample? For example, would you expect these new penguins to fall on the wiggly model 9 curve?

 

## Exercise 6: Overfitting

Model 9 provides an example of a model that is **overfit** to our sample data. That is, it picks up the tiny details of our data at the cost of losing the more general trends of the relationship of interest. Check out the following [xkcd comic](https://xkcd.com/2048/). Which plot pokes fun at overfitting?

![](https://imgs.xkcd.com/comics/curve_fitting_2x.png)


Some other goodies:

![](https://pbs.twimg.com/media/EbI7FNxX0AU_gIR.jpg)

![](https://miro.medium.com/max/800/1*cT-z5lx-c0phjaw-iVUxvA.jpeg)



## Exercise 7: Questioning R-squared
 
Zooming out, explain some limitations of relying on R-squared to measure the strength / usefulness of a model.


## Exercise 8: Adjusted R-squared

We've seen that, unless a predictor is redundant with another, R-squared will increase. Even if that predictor is strongly multicollinear with another. Even if that predictor isn't a good predictor! Thus if we only look at R-squared we might get overly greedy. We can check our greedy impulses a few ways. We take a more in depth approach in STAT 253, but one quick alternative is reported right in our model `summary()` tables. **Adjusted R-squared** includes a *penalty* for incorporating more and more predictors. Mathematically (where $n$ is the sample size and $p$ is the number of non-intercept coefficients):

$$
\text{Adjusted } R^2 = 1 - (1 - R^2) \left( \frac{n-1}{n-p-1} \right)
$$

Thus unlike R-squared, Adjusted R-squared can *decrease* when the information that a predictor contributes to a model isn't enough to offset the complexity it adds to that model. Consider two models:

```{r}
example_1 <- lm(bill_len ~ species, penguins)
example_2 <- lm(bill_len ~ species + island, penguins)
summary(example_1)
summary(example_2)
```

a. Check out the summaries for the 2 example models. In general, how does a model's Adjusted R-squared compare to the R-squared? Is it greater, less than, or equal to the R-squared?
b. How did the R-squared change from example model 1 to model 2? How did the Adjusted R-squared change?
c. Explain what it is about `island` that resulted in a decreased Adjusted R-squared. Note: it's not necessarily the case that `island` is a bad predictor on its own!








\
\
\
\



# Solutions

```{r eval = TRUE, echo = FALSE}
# Load packages & data
library(tidyverse)
data(penguins)

penguins <- penguins %>% 
    mutate(flipper_len = flipper_len / 10)

penguin_model_1 <- lm(bill_len ~ flipper_len, penguins)
penguin_model_2 <- lm(bill_len ~ flipper_len, penguins)
penguin_model_3 <- lm(bill_len ~ flipper_len + flipper_len, penguins)
penguin_model_4 <- lm(bill_len ~ body_mass, penguins)
penguin_model_5 <- lm(bill_len ~ flipper_len + body_mass, penguins)
```


## Exercise 1: Modeling bill length by flipper length

model              predictors
------------------ ---------------------------
`penguin_model_1`  `flipper_len`
`penguin_model_2`  `flipper_len`
`penguin_model_3`  `flipper_len + flipper_len`


Plots of the first two models are below:

```{r eval = TRUE}
ggplot(penguins, aes(y = bill_len, x = flipper_len)) + 
    geom_point() +
    geom_smooth(method = "lm", se = FALSE)

ggplot(penguins, aes(y = bill_len, x = flipper_len)) + 
    geom_point() +
    geom_smooth(method = "lm", se = FALSE)
```

a. Your intuition--answers will vary

b. The R-squared values are all the same!

```{r eval = TRUE}
summary(penguin_model_1)$r.squared
summary(penguin_model_2)$r.squared
summary(penguin_model_3)$r.squared
```

c. The two variables are perfectly linearly correlated---they contain exactly the same information!

```{r eval = TRUE}
ggplot(penguins, aes(x = flipper_len, y = flipper_len)) +
    geom_point()
```

d. An `NA` means that the coefficient couldn't be estimated. In `penguin_model_3`, the interpretation of the `flipper_len` coefficient is the average change in bill length per centimeter change in flipper length, while holding flipper length in millimeters constant...this is impossible! We can't hold flipper length in millimeters fixed while varying flipper length in centimeters---if one changes the other must. (In linear algebra terms, the matrix underlying our data is not of full rank.)



## Exercise 2: Incorporating `body_mass`   

In this exercise you'll consider 3 models of `bill_len`:

model              predictors
------------------ ---------------------------
`penguin_model_1`  `flipper_len`
`penguin_model_4`  `body_mass`
`penguin_model_5`  `flipper_len + body_mass`


a. `flipper_len` is a better predictor than `body_mass` because `penguin_model_1` has an R-squared value of 0.4306 vs 0.3542 for `penguin_model_4`.

b. Intuition check--answers will vary

c. R-squared is for `penguin_model_5` which is slightly higher than that of `penguin_model_1` and `penguin_model_4`.

d.`flipper_len` and `body_mass` are positively correlated and thus contain related information, but not completely redundant information. There's some information in flipper length in explaining bill length that isn't captured by body mass, and vice-versa.

```{r eval = TRUE}
ggplot(penguins, aes(x = flipper_len, y = body_mass)) +
    geom_point()
```



## Exercise 3: Redundancy and Multicollinearity

model              predictors
------------------ ---------------------------
`penguin_model_1`  `flipper_len`
`penguin_model_2`  `flipper_len`
`penguin_model_3`  `flipper_len + flipper_len`
`penguin_model_4`  `body_mass`
`penguin_model_5`  `flipper_len + body_mass`


a. `penguin_model_3` had *redundant* predictors: ``flipper_len` and `flipper_len`
b. `penguin_model_5` had *multicollinear* predictors: `flipper_len`  and `body_mass` were related but not redundant
c. R-squared  will stay the same if we add a *redundant* predictor to a model.
d. R-squared will increase by a small amount if we add a *multicollinear* predictor to a model.



## Exercise 4: Considerations for strong models

a. A gut check! Answers will vary
b. Based on R-squared: recall that R-squared is interpreted as the proportion of variation in the outcome that our model explains. It would seem that higher is better, so `poly_mod_9` might seem to be the best. BUT we'll see where this reasoning is flawed soon!
c. Based on the plots: Answers will vary



## Exercise 5: Reflecting on these investigations

a. salmon, chocolate, samosas. Together? Yuck!
b. Regarding model 9:
    - NOT easy to interpret.
    - NO. It's much more wiggly than the general trend.
    - NOT WELL. It is too tailored to our data.

 

## Exercise 6: Overfitting

The bottom left plot pokes fun at overfitting.

![](https://imgs.xkcd.com/comics/curve_fitting_2x.png)



## Exercise 7: Questioning R-squared
 
It measures how well our model explains / predicts *our* sample data, not how well it explains / predicts the broader population. It also has the feature that *any non-redundant* predictor added to a model will increase the R-squared.


## Exercise 8: Adjusted R-squared

a. Adjusted R-squared is less than the R-squared
b. From model 1 to 2, R-squared increased and Adjusted R-squared decreased.
c. `island` didn't provide useful information about bill length beyond what was already provided by species.



