Applied Linear Models

STAT3530 Fall 2026

Understanding model fit

The other perspective on model quality: how much variation does it explain?

Compare:

  • the total variability of \(Y\)
  • the residual variability after adjusting for \(x\)

We can partition variation:

\[\underbrace{\sum_i (Y_i - \bar{Y})^2}_{\text{total}:\;SST} \;=\; \underbrace{\sum_i (\hat{Y}_i - \bar{Y})^2}_{\text{model}:\;SSR} \;+\; \underbrace{\sum_i (Y_i - \hat{Y}_i)^2}_{\text{residual}:\;SSE}\]

The standard measure of fit quality is the share of variation explained by the model: \[R^2 = \frac{SSR}{SST} = 1 - \frac{SSE}{SST}\]

Measuring model fit

Adding predictors always increases \(R^2\), even if modestly.

# update the model with a noise variable
set.seed(92926)
extra <- update(full, ~ . + rnorm(n = 30, mean = 0, sd = 4))

# compare r squared
c(original = summary(full)$r.squared, 
  with.noise = summary(extra)$r.squared)
  original with.noise 
 0.6517747  0.6540445 

We can add an adjustment for the number of variables in the model \[ R^2_{\text{adj}} = 1 - \frac{SSE/(n-p)}{SST/(n-1)} \]

# compare adjusted r squared
c(original = summary(full)$adj.r.squared, 
  with.noise = summary(extra)$adj.r.squared)
  original with.noise 
 0.6115948  0.5986917 

So the model explains an estimated 61% of variation in taste scores.

The omnibus F test

Idea: test whether the model explains a significant amount of variation.

Suppose no predictor is associated with the response, i.e., \(H_0: \beta_1 = \cdots = \beta_{p-1} = 0\).

Under \(H_0\) and error normality, the relative share of variation explained by the model has a tractable sampling distribution: \[ F = \frac{n - p}{p - 1} \times \frac{SSR}{SSE} \sim F_{p-1,\,n-p} \]

For the cheddar data the statistic is way out in the tail:

summary(full)$fstatistic
   value    numdf    dendf 
16.22143  3.00000 26.00000 

So the data provide evidence that the model explains a significant amount of variation.

That other stuff in the output

Check the bottom of the model summary for \(R^2\), adjusted \(R^2\), and the omnibus test.

summary(full)

Call:
lm(formula = taste ~ Acetic + H2S + Lactic, data = cheddar)

Residuals:
    Min      1Q  Median      3Q     Max 
-17.390  -6.612  -1.009   4.908  25.449 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept) -28.8768    19.7354  -1.463  0.15540   
Acetic        0.3277     4.4598   0.073  0.94198   
H2S           3.9118     1.2484   3.133  0.00425 **
Lactic       19.6705     8.6291   2.280  0.03108 * 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 10.13 on 26 degrees of freedom
Multiple R-squared:  0.6518,    Adjusted R-squared:  0.6116 
F-statistic: 16.22 on 3 and 26 DF,  p-value: 3.81e-06
  • the data provide evidence that at least one compound is associated with taste
  • the compounds explain 61% of variance in taste scores

Another look at multicollinearity

Recall the car seat data: hipcenter on eight body measurements, for 38 drivers.

summary(seat)

Call:
lm(formula = hipcenter ~ ., data = seatpos)

Residuals:
    Min      1Q  Median      3Q     Max 
-73.827 -22.833  -3.678  25.017  62.337 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)  
(Intercept) 436.43213  166.57162   2.620   0.0138 *
Age           0.77572    0.57033   1.360   0.1843  
Weight        0.02631    0.33097   0.080   0.9372  
HtShoes      -2.69241    9.75304  -0.276   0.7845  
Ht            0.60134   10.12987   0.059   0.9531  
Seated        0.53375    3.76189   0.142   0.8882  
Arm          -1.32807    3.90020  -0.341   0.7359  
Thigh        -1.14312    2.66002  -0.430   0.6706  
Leg          -6.43905    4.71386  -1.366   0.1824  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 37.72 on 29 degrees of freedom
Multiple R-squared:  0.6866,    Adjusted R-squared:  0.6001 
F-statistic:  7.94 on 8 and 29 DF,  p-value: 1.306e-05

Classic multicollinearity signature:

  • omnibus test is significant
  • but none of the partial tests are

So the fit says that some predictors matter but can’t identify which.

Perspectives on F tests

There are a few (equivalent) ways of looking at what’s being tested.

  1. Coefficient values: is at least one coefficient in the set nonzero?

    \[ H_0: \beta_1 = \cdots = \beta_{p-1} = 0 \quad\text{vs}\quad H_A: \beta_j \neq 0 \text{ for some } j > 0 \]

  2. Explanatory significance: do the predictors collectively explain a significant amount of variation in the response?

    \[ H_0: \mathbb{E}\left[\frac{SSR}{p-1}\right] = \sigma^2 \quad\text{vs}\quad H_A: \mathbb{E}\left[\frac{SSR}{p-1}\right] > \sigma^2 \]

  3. Model comparison: is the model “better” than a null (intercept-only) model?

    \[ H_0: \mathcal{M}_0 \quad\text{vs}\quad H_A: \mathcal{M}_1 \]

Model comparisons

The omnibus F test compares the models

\[\begin{align*} \mathcal{M}_0: Y_i &= \beta_0 + \epsilon_i \qquad&\text{null model} \\ \mathcal{M}_1: Y_i &= \beta_0 + \beta_1 x_{i1} + \cdots + \beta_{p-1} x_{i\,p-1} + \epsilon_i \qquad&\text{full model} \\ \end{align*}\]

Under \(\mathcal{M}_0\), the fitted values are \(\hat{Y}_i = \hat\beta_0 = \bar{Y}\) for every observation, so

\[ SSE_0 = \sum_i (Y_i - \hat{Y}_i)^2 = \sum_i (Y_i - \bar{Y})^2 = SST \]

Recalling that \(SST = SSR_1 + SSE_1\) under \(\mathcal{M}_1\), we can rewrite the F statistic as \[ F = \frac{n-p}{p-1}\times\frac{SSR_1}{SSE_1} = \frac{n-p}{p-1}\times\frac{SSE_0 - SSE_1}{SSE_1} \]

It turns out that one can construct F tests to compare any nested models.

Nesting

\(\mathcal{M}_0\) is nested in \(\mathcal{M}_1\) if \(\mathcal{M}_0 \subseteq \mathcal{M}_1\). But what is model containment?

Formally, a model \(\mathcal{M}\) specifies that the mean lives in a subspace: \[ \mathbb{E}_\mathcal{M} [Y] \in V \subseteq \mathbb{R}^n \]

In the general linear model one has \[ \mathbb{E}[Y] = X\beta \in \text{col}(X) \]

The intercept-only model is nested in the full model because \[ \text{span}\{\mathbf{1}\} \subseteq \text{col}(X) \]

Geometry of the F test

So for the omnibus F test we have

\[\begin{align*} \mathcal{M}_0: Y &= \mathbf{1}\mu + \epsilon \qquad&\text{null model} \\ \mathcal{M}_1: Y &= X\beta + \epsilon \qquad&\text{full model} \\ \end{align*}\]

with the implied subspaces \(V_0 = \text{span}\{\mathbf{1}\}\) and \(V_1 = \text{col}(X)\).

Least squares under each model gives the projections \[\begin{align*} H_0 &= \frac{1}{n}\mathbf{1}\mathbf{1}^T\\ H_1 &= X(X^TX)^{-1}X^T \end{align*}\]

The error each model leaves behind is the distance from \(Y\) to its own subspace.

The geometry of the F test

The “extra sum of squares” measures the distance between model fits.

\[ \underbrace{\|H_1Y - H_0Y\|^2}_\text{extra SS} = SSE_0 - SSE_1 \]

So the F test is assessing whether the extra SS is large enough to support the full model: \[ F = \underbrace{\frac{SSE_0 - SSE_1}{SSE_1}}_\text{relative change in fit} \;\Big/\; \underbrace{\frac{\dim V_1 - \dim V_0}{n - \dim V_1}}_\text{relative change in df} \]

Reconstructing the omnibus test

Revisiting the cheddar data, recall:

# f statistic
summary(full)$fstat
   value    numdf    dendf 
16.22143  3.00000 26.00000 

We can obtain this via a model comparison:

# full model
m1 <- lm(taste ~ ., data = cheddar)

# reduced model
m0 <- lm(taste ~ 1, data = cheddar)

# extra sum of squares F test
anova(m0, m1)
Analysis of Variance Table

Model 1: taste ~ 1
Model 2: taste ~ Acetic + H2S + Lactic
  Res.Df    RSS Df Sum of Sq      F   Pr(>F)    
1     29 7662.9                                 
2     26 2668.4  3    4994.5 16.221 3.81e-06 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

In the ANOVA table:

  • Res.DF reports \(n - \text{dim}V\)
  • RSS reports \(SSE\)
  • Df reports the change in degrees of freedom
  • Sum of Sq reports the extra sum of squares

The extra sum of squares F test

The F test works for any nested models \(\mathcal{M}_0, \mathcal{M}_1\) for which \(V_0, V_1\) are linear subspaces.

\[ F = \underbrace{\frac{SSE_0 - SSE_1}{SSE_1}}_\text{relative change in fit} \;\Big/\; \underbrace{\frac{\dim V_1 - \dim V_0}{n - \dim V_1}}_\text{relative change in df} \]

We can then test hypotheses such as:

  • (predictor subset) \(H_0: \beta_{1} = \beta_{2} = 0\)
  • (contrast) \(H_0: \beta_1 - \beta_2 = 0\)

Example: savings rates

Savings rates (sr) in 50 countries, with two demographic and two economic predictors.

head(savings)
             sr pop15 pop75     dpi ddpi
Australia 11.43 29.35  2.87 2329.68 2.87
Austria   12.07 23.32  4.41 1507.99 3.93
Belgium   13.17 23.80  4.43 2108.47 3.82
Bolivia    5.75 41.89  1.67  189.13 0.22
Brazil    12.88 42.19  0.83  728.47 4.56
Canada     8.79 31.72  2.85 2982.88 2.43
  • pop15: percent population under 15
  • pop75: percent population over 75
  • dpi: per-capita disposable income
  • ddpi: percent growth in dpi

Question: does the age structure of a population matter?

m1 <- lm(sr ~ ., data = savings) # full model
m0 <- lm(sr ~ dpi + ddpi, data = savings) # reduced model
anova(m0, m1)
Analysis of Variance Table

Model 1: sr ~ dpi + ddpi
Model 2: sr ~ pop15 + pop75 + dpi + ddpi
  Res.Df    RSS Df Sum of Sq      F   Pr(>F)   
1     47 824.72                                
2     45 650.71  2       174 6.0167 0.004835 **
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Your turn

Savings rates (sr) in 50 countries, with two demographic and two economic predictors.

head(savings)
             sr pop15 pop75     dpi ddpi
Australia 11.43 29.35  2.87 2329.68 2.87
Austria   12.07 23.32  4.41 1507.99 3.93
Belgium   13.17 23.80  4.43 2108.47 3.82
Bolivia    5.75 41.89  1.67  189.13 0.22
Brazil    12.88 42.19  0.83  728.47 4.56
Canada     8.79 31.72  2.85 2982.88 2.43
  • pop15: percent population under 15
  • pop75: percent population over 75
  • dpi: per-capita disposable income
  • ddpi: percent growth in dpi

How would you test whether economic structure matters? Write the models to compare.

m1 <- lm(sr ~ ., data = savings) # full model
m0 <- lm(sr ~ pop15 + pop75, data = savings) # reduced model
anova(m0, m1)
Analysis of Variance Table

Model 1: sr ~ pop15 + pop75
Model 2: sr ~ pop15 + pop75 + dpi + ddpi
  Res.Df    RSS Df Sum of Sq     F  Pr(>F)  
1     47 726.17                             
2     45 650.71  2    75.455 2.609 0.08471 .
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Partial \(t\) tests are also F tests

Consider the usual coefficient summary:

sv <- lm(sr ~ pop15 + pop75 + dpi + ddpi, 
         data = savings)
summary(sv)$coefficients
                 Estimate   Std. Error    t value     Pr(>|t|)
(Intercept) 28.5660865407 7.3545161062  3.8841558 0.0003338249
pop15       -0.4611931471 0.1446422248 -3.1885098 0.0026030189
pop75       -1.6914976767 1.0835989307 -1.5609998 0.1255297940
dpi         -0.0003369019 0.0009311072 -0.3618293 0.7191731554
ddpi         0.4096949279 0.1961971276  2.0881801 0.0424711387

The partial test on ddpi tests whether \(H_0: \beta_{4} = 0\), which we can test via

m0 <- lm(sr ~ pop15 + pop75 + dpi, data = savings)
anova(m0, sv)
Analysis of Variance Table

Model 1: sr ~ pop15 + pop75 + dpi
Model 2: sr ~ pop15 + pop75 + dpi + ddpi
  Res.Df    RSS Df Sum of Sq      F  Pr(>F)  
1     46 713.77                              
2     45 650.71  1    63.054 4.3605 0.04247 *
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

The \(p\)-values are identical, and in fact \(F = T^2\).

Contrasts

A contrast is a linear function of the parameters: \(c^T\beta\).

Consider the cheddar model with standardized predictors:

fit.s <- lm(taste ~ Acetic + H2S + Lactic, data = cs)
summary(fit.s)$coefficients |> round(3)
            Estimate Std. Error t value Pr(>|t|)
(Intercept)   24.533      1.850  13.264    0.000
Acetic         0.187      2.546   0.073    0.942
H2S            8.320      2.655   3.133    0.004
Lactic         5.970      2.619   2.280    0.031

The magnitude of association is a bit larger for H2S. Suppose we want to test that.

The corresponding hypothesis is a contrast \[ H_0: \beta_2 = \beta_3 \qquad\Longleftrightarrow\qquad H_0: c^T \beta = 0 \qquad\text{where}\qquad c^T = [\,0\;\;0\;\;1\;\;-1\,] \]

Testing a contrast

The hypothesis \(H_0: c^T\beta = 0\) is a linear constraint that defines a reduced model subspace via

\[V_0 = \{X\beta : c^T\beta = 0\} \qquad\text{with}\qquad \dim V_0 = p - 1\]

So the extra sum of squares F test works, if we can sort out how to compute \(SSE_0\).

The car package provides an implementation which requires only \(c^T\):

car::linearHypothesis(fit.s, hypothesis.matrix = c(0, 0, -1, 1))

Linear hypothesis test:
- H2S  + Lactic = 0

Model 1: restricted model
Model 2: taste ~ Acetic + H2S + Lactic

  Res.Df    RSS Df Sum of Sq     F Pr(>F)
1     27 2696.8                          
2     26 2668.4  1    28.432 0.277 0.6031

So there is no evidence the two differ.