-
Notifications
You must be signed in to change notification settings - Fork 539
Expand file tree
/
Copy path10-inference-for-regression.qmd
More file actions
2894 lines (2219 loc) · 167 KB
/
Copy path10-inference-for-regression.qmd
File metadata and controls
2894 lines (2219 loc) · 167 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
description: &desc "Apply confidence intervals and hypothesis tests to regression slopes, check the LINE conditions, and read diagnostic plots."
open-graph:
description: *desc
twitter-card:
description: *desc
---
```{r setup-init, include=FALSE}
library(knitr)
source("scripts/image_functions.R")
```
# Inference for Regression {#sec-inference-for-regression}
::: {.callout-note title="In this chapter, you'll learn how to:"}
- Apply confidence intervals and hypothesis tests to regression coefficients (slope, intercept)
- Check the **LINE conditions** (Linearity, Independence, Normality, Equality of variance) for regression inference
- Compare *theory-based* and *simulation-based* approaches to regression inference
- Use diagnostic plots (residual vs. fitted, QQ-plot) to assess model assumptions
:::
```{r setup_inference_regression, include=FALSE, purl=FALSE}
# Used to define Learning Check numbers:
chap <- 10
lc <- 0
# Set R code chunk defaults:
opts_chunk$set(
echo = TRUE,
eval = TRUE,
warning = FALSE,
message = TRUE,
tidy = FALSE,
purl = TRUE,
out.width = "\\textwidth",
# fig.height = 4,
fig.align = "center"
)
# Set output digit precision
options(scipen = 99, digits = 3)
# Set random number generator see value for replicable pseudo-randomness.
set.seed(76)
```
```{r lc-inline-setup-10, include=FALSE, purl=FALSE}
source("scripts/lc_solutions.R")
lc_setup(10)
```
In this chapter, we revisit the regression model studied in @sec-regression and @sec-multiple-regression.
We do it by taking into account the inferential statistics methods introduced in @sec-confidence-intervals and @sec-hypothesis-testing.
We will show that when applying the linear regression methods introduced earlier on sample data, we can gain insight into the relationships between the response and explanatory variables of an entire population.
## Needed packages {#sec-inf-packages .unnumbered}
If needed, read @sec-packages for information on how to install and load R packages.
```{r inference-for-regression-load-packages, message=FALSE}
library(tidyverse)
library(moderndive)
library(infer)
library(gridExtra)
library(GGally)
```
Recall that loading the `tidyverse` package loads many packages that we have encountered earlier. For details refer to @sec-tidyverse-package. The packages `moderndive` and `infer` contain functions and data frames that will be used in this chapter.
```{r inference-for-regression-load-internal, message=FALSE, echo=FALSE, purl=FALSE}
# Packages needed internally, but not in text.
library(tidyr)
library(kableExtra)
library(patchwork)
```
## The simple linear regression model
### UN member states revisited
We briefly review the example of UN member states covered in @sec-model1.
Data on the current UN member states, as of 2024, can be found in the `un_member_states_2024` data frame included in the `moderndive` package.
As we did in @sec-model1, we save these data as a new data frame called `UN_data_ch10`, `select()` the required variables, and include rows without missing data using `na.omit()`:
```{r inference-for-regression-create-UN_data_ch10}
UN_data_ch10 <- un_member_states_2024 |>
select(country,
life_exp = life_expectancy_2022,
fert_rate = fertility_rate_2022)|>
na.omit()
```
```{r inference-for-regression-demo-code, eval=FALSE}
UN_data_ch10
```
```{r inference-for-regression-create-n_UN_data_ch10, echo=FALSE}
n_UN_data_ch10 <- nrow(UN_data_ch10)
```
```{r inference-for-regression-select-vars, echo=FALSE}
un_member_states_2024 |>
select(life_exp = life_expectancy_2022,
fert_rate = fertility_rate_2022)|>
na.omit() |>
tidy_summary() |>
kbl() |>
kable_styling(
font_size = ifelse(is_latex_output(), 10, 16),
latex_options = c("HOLD_position")
)
```
Above we show the summary of the two numerical variables.
Observe that there are `r n_UN_data_ch10` observations without missing values.
Using simple linear regression \index{regression!simple linear} between the response variable fertility rate (`fert_rate`) or $y$, and the regressor life expectancy (`life_exp`) or $x$, the regression line is:
$$
\widehat{y}_i = b_0 + b_1 \cdot x_i.
$$
We have presented this equation in @sec-model1, but we now add the subscript $i$ to represent the $i$th observation or country in the UN dataset, and we let $i = 1$, $\dots$, $n$ with $n = `r n_UN_data_ch10`$ for this UN data.
The value $x_i$ represents the life expectancy value for the $i$th member state, and $\widehat{y}_i$ is the fitted fertility rate for the $i$th member state.
The fitted fertility rate is the result of the regression line and is typically different than the observed response $y_i$.
The residual is given as the difference $y_i - \widehat{y}_i$.
As discussed in @sec-leastsquares, the intercept ($b_0$) and slope ($b_1$) are the regression coefficients, such that the regression line is the "best-fitting" line based on the least-squares criterion.
In other words, the fitted values $\widehat{y}$ calculated using the least-squares coefficients ($b_0$ and $b_1$) minimize the *sum of the squared residuals*:
$$
\sum_{i=1}^{n}(y_i - \widehat{y}_i)^2
$$
As we did in @sec-model1, we fit the linear regression model.
By "fit" we mean to calculate the regression coefficients, $b_0$ and $b_1$, that minimize the sum of squared residuals.
To do this in R, we use the `lm()` function with the formula `fert_rate ~ life_exp` and save the solution in `simple_model`:
```{r inference-for-regression-lm-fertility, eval=FALSE}
simple_model <- lm(fert_rate ~ life_exp, data = UN_data_ch10)
coef(simple_model)
```
```{r inference-for-regression-create-simple_model, echo=FALSE, purl=FALSE}
# Fit regression model:
simple_model <- lm(fert_rate ~ life_exp,
data = UN_data_ch10)
b0 <- round(coef(simple_model),2)
# Get the coefficients of the model
lm_data <- data.frame("Coefficients" = c("b0", "b1"),
"Values" = coefficients(simple_model))
kbl(lm_data)|>
kable_styling(
font_size = ifelse(is_latex_output(), 10, 16),
latex_options = c("HOLD_position")
)
```
The regression line is $\widehat{y}_i = b_0 + b_1 \cdot x_i = `r lm_data$Values[1]` - `r abs(lm_data$Values[2])` \cdot x_i$, where $x_i$ is the life expectancy for the $i$th country and $\widehat{y}_i$ is the corresponding fitted fertility rate.
The $b_0$ coefficient is the intercept and has a meaning only if the range of values of the regressor, $x_i$, includes zero.
Since life expectancy is always a positive value, we do not provide any interpretation to the intercept in this example.
The $b_1$ coefficient is the slope of the regression line; for any country, if the life expectancy were to increase by about one year, we would expect an associated reduction of the fertility rate by about 0.137 units.
We visualize the relationship of the data observed in @fig-regline-ch10 by plotting the scatterplot of fertility rate against life expectancy for all the UN member states with complete data.
We also include the regression line using the least-squares criterion:
```{r fig-regline-ch10, fig.alt="Scatterplot of two variables with a fitted regression line overlaid, used as a generic example.", fig.cap="Relationship with regression line.", fig.height=ifelse(knitr::is_latex_output(), 3, 4), message=FALSE}
ggplot(UN_data_ch10, aes(x = life_exp, y = fert_rate)) +
geom_point() +
labs(x = "Life Expectancy (x)",
y = "Fertility Rate (y)",
title = "Relationship between fertility rate and life expectancy") +
geom_smooth(method = "lm", se = FALSE, linewidth = 0.5)
```
Finally, we review how to determine the fitted values and residuals for observations in the dataset.
France is one of the UN member states, and suppose we want to determine the fitted fertility rate for France based on the linear regression.
We start by determining what is the location of France in the `UN_data_ch10` data frame, using `rowid_to_column()` and `filter()` with the variable country equal to "France."
The `pull()` function converts the row number as a data frame to a single value:
```{r inference-for-regression-filter, eval=FALSE}
UN_data_ch10 |>
rowid_to_column() |>
filter(country == "France")|>
pull(rowid)
```
```{r inference-for-regression-create-france_id, echo=FALSE}
france_id <- UN_data_ch10 |>
rowid_to_column() |>
filter(country == "France")|>
pull(rowid)
france_id
```
France is the `r france_id`th member state in `UN_data_ch10`. Its observed fertility rate and life expectancy are:
```{r inference-for-regression-filter-alt, eval=FALSE}
UN_data_ch10 |>
filter(country == "France")
```
```{r inference-for-regression-create-france_data, echo=FALSE}
france_data <- UN_data_ch10 |>
filter(country == "France")
france_data
```
```{r inference-for-regression-create-actual_france, echo=FALSE}
actual_france <- france_data$fert_rate[1]
fitted_france <- lm_data$Values[1] - abs(lm_data$Values[2]) * france_data$life_exp[1]
resid_france <- actual_france - fitted_france
```
France's life expectancy is $x_{`r france_id`} = `r france_data$life_exp[1]`$ years and the fertility rate is $y_{`r france_id`} =`r france_data$fert_rate[1]`$.
Using the regression line from earlier, we can determine France's fitted fertility rate:
$$
\begin{aligned}
\widehat{y}_{57} &= `r lm_data$Values[1]` - `r abs(lm_data$Values[2])` \cdot x_{`r france_id`}\\
&= `r lm_data$Values[1]` - `r abs(lm_data$Values[2])` \cdot `r france_data$life_exp[1]`\\
&= `r fitted_france`.
\end{aligned}
$$
Based on our regression line we would expect France's fertility rate to be `r lm_data$Values[1] - abs(lm_data$Values[2]) * france_data$life_exp[1]`.
The observed fertility rate for France was `r france_data$fert_rate[1]`, so the residual for France is $y_{`r france_id`} - \widehat{y}_{`r france_id`} = `r actual_france` - `r fitted_france` = `r resid_france`$.
Using R we are not required to manually calculate the fitted values and residual for each UN member state.
We do this directly using the regression model `simple_model` and the `get_regression_points()` function.
To do this only for France, we `filter()` the `r france_id`th observation in the data frame.
```{r inference-for-regression-filter-alt2, eval=FALSE}
simple_model |>
get_regression_points() |>
filter(ID == 57)
```
```{r fittedtable-ch10, echo=FALSE, purl= FALSE}
get_regression_points(simple_model) |>
filter(ID == 57)|>
kbl()|>
kable_styling(
font_size = ifelse(is_latex_output(), 10, 16),
latex_options = c("HOLD_position")
)
```
We can retrieve this information for each observation.
Here we show the first few rows:
```{r fittedtable-ch10-all}
simple_model |>
get_regression_points()
```
This concludes our review of material covered in @sec-model1. We now explain how to use this information for statistical inference.
### The model {#sec-simple-linear-model}
As we did in @sec-confidence-intervals on confidence intervals and @sec-hypothesis-testing on hypothesis testing, we present this problem in the context of a population and associated parameters of interest.
We then collect a random sample from this population and use it to estimate these parameters.
We assume that this population has a response variable ($Y$), an explanatory variable ($X$), and there is a *statistical linear relationship* between these variables, given by the linear model
$$Y = \beta_0 + \beta_1 \cdot X + \epsilon,$$
where $\beta_0$ is the population intercept and $\beta_1$ is the population slope.
These are now the parameters of the model that alongside the explanatory variable ($X$) produce the equation of a line.
The statistical part of this relationship is given by $\epsilon$, a random variable called the *error term*.
The error term accounts for the portion of $Y$ that is not explained by the line.
We make additional assumptions about the distribution of the error term, $\epsilon$.
The assumed expected value of the error term is zero, and the assumed standard deviation is equal to a positive constant called $\sigma$, or in mathematical terms: $E(\epsilon) = 0$ and $SD(\epsilon) = \sigma.$
We review the meaning of these quantities.
If you were to take a large number of observations from this population, we would expect the error terms sometimes to be greater than zero and sometimes less than zero, but on average, be equal to zero.
Similarly, some error terms will be very close to zero and others very far from zero, but on average, we would expect them to be roughly $\sigma$ units away from zero.
Recall the square of the standard deviation is called the variance, so $Var(\epsilon) = \sigma^2$.
The variance of the error term is equal to $\sigma^2$ regardless of the value of $X$.
This property is called *homoskedasticity* or constancy of the variance.
It will be useful later on in our analysis.
### Using a sample for inference {#sec-sample-regression-inference}
As we did in @sec-confidence-intervals and @sec-hypothesis-testing, we use a sample to estimate the parameters in the population.
We use data collected from the Old Faithful Geyser in Yellowstone National Park in Wyoming, USA.
This dataset contains the `duration` of the geyser eruption in seconds and the `waiting` time to the next eruption in minutes.
The duration of the current eruption can help determine fairly well the waiting time to the next eruption.
For this example, we use a sample of data collected by volunteers and saved on the website [*https://geysertimes.org/*](https://geysertimes.org/) between June 1st, 2024 and August 19th, 2024.
These data are stored in the `old_faithful_2024` data frame in the `moderndive` package.
While data collected by volunteers are not a random sample, as the volunteers could introduce some sort of bias, the eruptions selected by the volunteers had no specific patterns.
Further, beyond the individual skill of each volunteer measuring the times appropriately, no response bias or preference seems to be present.
Therefore, it seems safe to consider the data a random sample. The first ten rows are shown here:
```{r inference-for-regression-demo-code-v2}
old_faithful_2024
```
By looking at the first row we can tell, for example, that an eruption on August 19, 2024, at 5:38 AM lasted 235 seconds, and the waiting time for the next eruption was 180 minutes.
We next display the summary for these two variables:
```{r inference-for-regression-demo-code-v2-dup1, eval=FALSE}
old_faithful_2024 |>
select(duration, waiting) |>
tidy_summary()
```
```{r inference-for-regression-select-vars-alt, echo=FALSE}
old_faithful_2024 |>
select(duration, waiting) |>
tidy_summary() |>
kbl() |>
kable_styling(
font_size = ifelse(is_latex_output(), 10, 16),
latex_options = c("HOLD_position")
)
```
```{r inference-for-regression-dynamic-text, echo=FALSE}
# This code is used for dynamic non-static in-line text output purposes
n_old_faithful <- dim(old_faithful_2024)[1]
```
We have a sample of `r n_old_faithful` eruptions, lasting between 99 seconds and 300 seconds, and the waiting time to the next eruption was between 102 minutes and 201 minutes.
Observe that each observation is a pair of values, the value of the explanatory variable ($X$) and the value of the response ($Y$). The sample takes the form:
$$\begin{array}{c}
(x_1,y_1)\\
(x_2, y_2)\\
\vdots\\
(x_n, y_n)\\
\end{array}$$
where, for example, $(x_2, y_2)$ is the pair of explanatory and response values, respectively, for the second observation in the sample.
More generally, we denote the $i$th pair by $(x_i, y_i)$, where $x_i$ is the observed value of the explanatory variable $X$ and $y_i$ is the observed value of the response variable $Y$.
Since the sample has $n$ observations we let $i=1$, $\dots$, $n$.
In our example $n = `r n_old_faithful`$, and $(x_2, y_2) = (`r old_faithful_2024[2,6][[1]]`, `r old_faithful_2024[2,4][[1]]`)$.
@fig-geyserplot1 shows the scatterplot for the entire sample with some transparency set to check for overplotting:
```{r fig-geyserplot1, fig.alt="Scatterplot of eruption duration (seconds) versus waiting time to the next eruption (minutes) for the Old Faithful geyser. Two distinct clusters of points are visible.", echo=F, fig.cap="Scatterplot of relationship of eruption duration and waiting time.", fig.height=ifelse(knitr::is_latex_output(), 3, 4)}
ggplot(old_faithful_2024,
aes(x = duration, y = waiting)) +
geom_point(alpha = 0.3) +
labs(x = "duration", y = "waiting")
```
The relationship seems positive and, to some extent, linear.
### The method of least squares {#sec-least-squares}
If the association of these variables is linear or approximately linear, we can apply the linear model described in @sec-simple-linear-model to each observation in the sample:
$$\begin{aligned}
y_1 &= \beta_0 + \beta_1 \cdot x_1 + \epsilon_1\\
y_2 &= \beta_0 + \beta_1 \cdot x_2 + \epsilon_2\\
\vdots & \phantom{= \beta_0 + \beta_1 \cdot + \epsilon_2 +}\vdots \\
y_n &= \beta_0 + \beta_1 \cdot x_n + \epsilon_n
\end{aligned}$$
We want to be able to use this model to describe the relationship between the explanatory variable and the response, but the parameters $\beta_0$ and $\beta_1$ are unknown to us.
We estimate these parameters using the random sample by applying the *least-squares* method introduced in @sec-model1.
We compute the estimators for the intercept ($\beta_0$) and slope ($\beta_1$) that minimize the *sum of squared residuals*:
$$\sum_{i=1}^n \left[y_i - (\beta_0 + \beta_1 \cdot x_i)\right]^2.$$
This is an optimization problem and to solve it analytically we require calculus and the topic goes beyond the scope of this book.
We provide a sketch of the solution here for those familiar with the method: using the expression above we find the partial derivative with respect to $\beta_0$ and equate that expression to zero, the partial derivative with respect to $\beta_1$ and equate that expression to zero, and use those two equations to solve for $\beta_0$ and $\beta_1$.
The solutions are the regression coefficients introduced first in @sec-model1: $b_0$ is the estimator of $\beta_0$ and $b_1$ is the estimator of $\beta_1$.
They are called the *least squares estimators* and their mathematical expressions are:
$$b_1 = \frac{\sum_{i=1}^n(x_i - \bar x)(y_i - \bar y)}{\sum_{i=1}^n(x_i - \bar x)^2} \text{ and } b_0 = \bar y - b_1 \cdot \bar x.$$
Furthermore, an *estimator* for the standard deviation of $\epsilon_i$ is given by
$$s = \sqrt{\frac{\sum_{i=1}^n \left[y_i - (b_0 + b_1 \cdot x_i)\right]^2}{n-2}} = \sqrt{\frac{\sum_{i=1}^n \left(y_i - \widehat{y}_i\right)^2}{n-2}}.$$
These or equivalent calculations are done in R when using the `lm()` function.
For `old_faithful_2024` we get the results shown in @tbl-regtable-ch10-1:
```{r inference-for-regression-fit-lm, eval=FALSE}
# Fit regression model:
model_1 <- lm(waiting ~ duration, data = old_faithful_2024)
# Get the coefficients and standard deviation for the model
coef(model_1)
sigma(model_1)
```
```{r tbl-regtable-ch10-1, echo=FALSE, purl=FALSE}
# Fit regression model:
model_1 <- lm(waiting ~ duration, data = old_faithful_2024)
b_coef <- round(coef(model_1),2)
# Get the coefficients of the model
lm_data <- data.frame("Coefficients" = c("b0", "b1", "s"),"Values" = c(coefficients(model_1),sigma(model_1)))
lm_data |>
kbl(
digits = 3,
caption = "Old Faithful geyser linear regression coefficients",
booktabs = TRUE,
linesep = ""
) |>
kable_styling(
font_size = ifelse(is_latex_output(), 10, 16),
latex_options = c("HOLD_position")
)
```
Based on these data and assuming the linear model is appropriate, we can say that for every additional second that an eruption lasts, the waiting time to the next eruption increases, on average, by 0.37 minutes.
Any eruption lasts longer than zero seconds, so the intercept has no meaningful interpretation in this example.
Finally, we roughly expect the waiting time for the next eruption to be 20.37 minutes away from the regression line value, on average.
### Properties of the least squares estimators {#sec-properties-least-squares}
The least squares method produces the *best-fitting* line by selecting the least squares estimators, $b_0$ and $b_1$, that make the sum of residual squares the smallest possible.
But the choice of $b_0$ and $b_1$ depends on the sample observed.
For every random sample taken from the data, different values for $b_0$ and $b_1$ will be determined.
In that sense, the least squares estimators, $b_0$ and $b_1$, are random variables and as such, they have very useful properties:
- $b_0$ and $b_1$ are unbiased estimators of $\beta_0$ and $\beta_1$, or using mathematical notation: $E(b_0) = \beta_0$ and $E(b_1) = \beta_1$.
This means that, for some random samples, $b_1$ will be greater than $\beta_1$ and for others less than $\beta_1$.
On average, $b_1$ will be equal to $\beta_1$.
- $b_0$ and $b_1$ are linear combinations of the observed responses $y_1$, $y_2$, $\dots$, $y_n$.
This means that, for example for $b_1$, there are known constants $c_1$, $c_2$, $\dots$, $c_n$ such that $b_1 = \sum_{i=1}^n c_iy_i$.
- $s^2$ is an unbiased estimator of the variance $\sigma^2$.
These properties will be useful in the next subsection, once we perform theory-based inference for regression.
### Relating basic regression to other methods
To wrap-up this section, we'll be investigating how regression relates to two different statistical techniques. One of them was covered already in this book, the difference in sample means, and the other is new to the text but is related, ANOVA. We'll see how both can be represented in the regression framework. <!-- The hope is that this subsection helps you to tie together many of the concepts you've seen in the Statistical/Data Modeling and Statistical Inference parts of this book.-->
#### Two-sample difference in means {.unnumbered}
The two-sample difference in means is a common statistical technique used to compare the means of two groups as seen in @sec-ht-case-study. It is often used to determine if there is a significant difference in the mean response between two groups, such as a treatment group and a control group. The two-sample difference in means can be represented in the regression framework by using a dummy variable to represent the two groups.
Let's again consider the `movies_sample` data frame in the `moderndive` package. We'll compare once more the average rating for the genres of "Action" versus "Romance." We can use the `lm()` function to fit a linear model with a dummy variable for the genre and then use [`get_regression_table()`](https://moderndive.github.io/moderndive/reference/get_regression_table.html):
```{r inference-for-regression-assign-mod_diff_means, eval=FALSE}
mod_diff_means <- lm(rating ~ genre, data = movies_sample)
get_regression_table(mod_diff_means)
```
```{r tbl-diff-means-reg, echo=FALSE}
mod_diff_means <- lm(rating ~ genre, data = movies_sample)
get_regression_table(mod_diff_means) |>
kbl(caption = "Regression table for two-sample difference in means example") |>
kable_styling(
font_size = ifelse(is_latex_output(), 8, 16),
latex_options = c("HOLD_position")
)
```
Note from @tbl-diff-means-reg that `p_value` for the `genre: Romance` row is the $p$-value for the hypothesis test of
$$
H_0: \text{action and romance have the same mean rating}
$$
$$
H_A: \text{action and romance have different mean ratings}
$$
This $p$-value result matches closely with what was found in @sec-ht-case-study, but here we are using a theory-based approach with a linear model. The `estimate` for the `genre: Romance` row is the observed difference in means between the "Action" and "Romance" genres that we also saw in @sec-ht-case-study, except the sign is switched since the "Action" genre is the reference level.
#### ANOVA {.unnumbered}
ANOVA, or analysis of variance, is a statistical technique used to compare the means of three or more groups by seeing if there is a statistically significant difference between the means of multiple groups. ANOVA can be represented in the regression framework by using dummy variables to represent the groups. Let's say we wanted to compare the `popularity` (numeric) values in the `spotify_by_genre` data frame from the `moderndive` package across the genres of `country`, `hip-hop`, and `rock`. We use the `slice_sample()` function after narrowing in on our selected columns and filtered rows of interest to see what a few rows of this data frame look like in @tbl-spotify-for-anova-slice-five.
```{r inference-for-regression-create-spotify_for_anova, echo=-1}
set.seed(6)
spotify_for_anova <- spotify_by_genre |>
select(artists, track_name, popularity, track_genre) |>
filter(track_genre %in% c("country", "hip-hop", "rock"))
```
```{r inference-for-regression-sample-rows, eval=FALSE}
spotify_for_anova |>
slice_sample(n = 5)
```
```{r tbl-spotify-for-anova-slice-five, echo=FALSE}
spotify_for_anova |>
slice_sample(n = 5) |>
kbl(caption = "(ref:spotify-for-anova-slice)") |>
kable_styling(
font_size = ifelse(is_latex_output(), 8, 16),
latex_options = c("HOLD_position")
)
```
Before we fit a linear model, let's take a look at the boxplot of `track_genre` versus `popularity` in @fig-pop-by-genre-plot to see if there are any differences in the distributions of the three genres.
```{r fig-pop-by-genre-plot, fig.alt="Side-by-side boxplots of song popularity by music genre, showing differences in median and spread across genres.", fig.cap="Boxplot of popularity by genre.", fig.height=ifelse(knitr::is_latex_output(), 3.2, 4)}
ggplot(spotify_for_anova, aes(x = track_genre, y = popularity)) +
geom_boxplot() +
labs(x = "Genre", y = "Popularity")
```
We can also compute the mean `popularity` grouping by `track_genre`:
```{r inference-for-regression-grouped-summary}
mean_popularities_by_genre <- spotify_for_anova |>
group_by(track_genre) |>
summarize(mean_popularity = mean(popularity))
mean_popularities_by_genre
```
We can use the `lm()` function to fit a linear model with dummy variables for the genres. We'll then use the [`get_regression_table()`](https://moderndive.github.io/moderndive/reference/get_regression_table.html) function to get the regression table in @tbl-anova-reg-table.
```{r inference-for-regression-assign-mod_anova, eval=FALSE}
mod_anova <- lm(popularity ~ track_genre, data = spotify_for_anova)
get_regression_table(mod_anova)
```
```{r tbl-anova-reg-table, echo=FALSE}
mod_anova <- lm(popularity ~ track_genre, data = spotify_for_anova)
get_regression_table(mod_anova) |>
kbl(caption = "Regression table for ANOVA example") |>
kable_styling(
font_size = ifelse(is_latex_output(), 10, 16),
latex_options = c("HOLD_position")
)
```
The `estimate` for the `track_genre: hip-hop` and `track_genre: rock` rows are the differences in means between the "hip-hop" and "country" genres and the "rock" and "country" genres, respectively. The "country" genre is the reference level. These values match up (with some rounding differences) to what is shown in `mean_popularities_by_genre`.
The `p_value` column corresponds to `hip-hop` having a statistically higher mean `popularity` compared to `country` with a value of close to 0 (reported as 0). It also gives us that `rock` does not have a statistically significant $p$-value at 0.153, which would make us inclined to say that `rock` does not have a significantly higher popularity compared to `country`.
The traditional ANOVA doesn't give this level of granularity. It can be performed using the `aov()` function and the `anova()` function via a pipe (`|>`):
```{r inference-for-regression-demo-code-v2-dup2}
aov(popularity ~ track_genre, data = spotify_for_anova) |>
anova()
```
The small $p$-value here of `2.2e-16` is very close to 0, which would lead us to reject the null hypothesis that the mean popularities are equal across the three genres. This is consistent with the results we found using the linear model. The traditional ANOVA results do not tell us which means are different from each other though, but the linear model does. ANOVA tells us only that a difference exists in the means of the groups.
::: {.learncheck}
**Learning Check**
**`r paste0("(LC", chap, ".", (lc <- lc + 1), ")")`** What does the error term $\epsilon$ in the linear model $Y = \beta_0 + \beta_1 \cdot X + \epsilon$ represent?
- A. The exact value of the response variable.
- B. The predicted value of the response variable based on the model.
- C. The part of the response variable not explained by the line.
- D. The slope of the linear relationship between $X$ and $Y$.
```{r lc-sol-10-01, echo=FALSE, results='asis', purl=FALSE}
cat(lc_solution(10, 1))
```
**`r paste0("(LC", chap, ".", (lc <- lc + 1), ")")`** Which of the following is a property of the least squares estimators $b_0$ and $b_1$?
- A. They are biased estimators of the population parameters $\beta_0$ and $\beta_1$.
- B. They are linear combinations of the observed responses $y_1, y_2, \ldots, y_n$.
- C. They are always equal to the population parameters $\beta_0$ and $\beta_1$.
- D. They depend on the specific values of the explanatory variable $X$ only.
```{r lc-sol-10-02, echo=FALSE, results='asis', purl=FALSE}
cat(lc_solution(10, 2))
```
**`r paste0("(LC", chap, ".", (lc <- lc + 1), ")")`** How can the difference in means between two groups be represented in a linear regression model?
- A. By adding an interaction term between the groups and the response variable.
- B. By fitting separate regression lines for each group and comparing their slopes.
- C. By including a dummy variable to represent the groups.
- D. By subtracting the mean of one group from the mean of the other and using this difference as the predictor.
```{r lc-sol-10-03, echo=FALSE, results='asis', purl=FALSE}
cat(lc_solution(10, 3))
```
:::
## Theory-based inference for simple linear regression {#sec-theory-simple-regression}
This section introduces the conceptual framework needed for theory-based inference for regression (see @sec-framework-simple-lm and @sec-se-simple-lm) and discusses the two most prominent methods for inference: confidence intervals (@sec-conf-intervals-b0-b1) and hypothesis tests (@sec-hypo-test-simple-lm).
Some of this material is slightly more technical than other sections in this chapter, but most of the material is illustrated by working with a real example and interpretations and explanations complement the theory. @sec-regression-table presents the R code needed to calculate relevant quantities for inference. Feel free to read this section first.
### Conceptual framework {#sec-framework-simple-lm}
We start by reviewing the assumptions of the linear model. We continue using the `old_faithful_2024` to illustrate some of this framework. Recall that we have a random sample of $n = `r n_old_faithful`$ observations.
Since we assume a linear relationship between the `duration` of an eruption and the `waiting` time to the next eruption, we can express the linear relationship for the $i$th observation as $y_i = \beta_0 + \beta_1 \cdot x_i + \epsilon_i$ for $i=1,\dots,n$. Observe that $x_i$ is the `duration` of the $i$th eruption in the sample, $y_i$ is the `waiting` time to the next eruption, and $\beta_0$ and $\beta_1$ are the population parameters that are considered constant.
The error term $\epsilon_i$ is a random variable that represents how different the observed response $y_i$ is from the expected response $\beta_0 + \beta_1 \cdot x_i$.
We can illustrate the role of the error term using two observations from our `old_faithful_2024` dataset.
We assume for now that the linear model is appropriate and truly represents the relationship between `duration` and `waiting` times.
We select the 49th and 51st observations in our sample by using the function `slice()` with the corresponding rows:
```{r inference-for-regression-demo-code-v2-dup3}
old_faithful_2024 |>
slice(c(49, 51))
```
Observe that the `duration` time is the same for both observations, but the response `waiting` time is different.
Assuming that the linear model is appropriate, both responses can be expressed as:
$$\begin{aligned}
y_{49} &= \beta_0 + \beta_1 \cdot 236 + \epsilon_{49}\\
y_{51} &= \beta_0 + \beta_1 \cdot 236 + \epsilon_{51}
\end{aligned}$$
but $y_{49} = 139$ and $y_{51} = 176$.
The difference in responses is due to the error term as it accounts for variation in the response not accounted for by the linear model.
In the linear model the error term $\epsilon_i$ has expected value $E(\epsilon_i) = 0$ and standard deviation $SD(\epsilon_i) = \sigma$.
Since a random sample is taken, we assume that any two error terms $\epsilon_i$ and $\epsilon_j$ for any two different eruptions $i$ and $j$ are independent.
In order to perform the theory-based inference we require one additional assumption.
We let the error term be normally distributed with an expected value (mean) equal to zero and a standard deviation equal to $\sigma$:
$$\epsilon_i \sim Normal(0, \sigma).$$
The population parameters $\beta_0$ and $\beta_1$ are constants.
Similarly, the `duration` of the $i$th eruption, $x_i$, is known and also a constant.
Therefore, the expression $\beta_0 + \beta_1 \cdot x_i$ is a constant. By contrast, $\epsilon_i$ is a normally distributed random variable.
The response $y_i$ (the `waiting` time for the $i$th eruption to the next) is the sum of the constant $\beta_0 + \beta_1 \cdot x_i$ and the normally distributed random variable $\epsilon_i$.
Based on properties of random variables and the normal distribution, we can state that $y_i$ is also a normally distribution random variable with mean equal to $\beta_0 + \beta_1 \cdot x_i$ and standard deviation equal to $\sigma$:
$$y_i \sim Normal(\beta_0 + \beta_1 x_i\,,\, \sigma)$$
for $i=1,\dots,n$.
Since $\epsilon_i$ and $\epsilon_j$ are independent, $y_i$ and $y_j$ are also independent for any $i \ne j$.
In addition, as stated in @sec-properties-least-squares, the least-squares estimator $b_1$ is a linear combination of the random variables $y_1, \dots, y_n$.
So $b_1$ is also a random variable!
What does this mean?
The coefficient for the slope results from *a particular sample* of $n$ pairs of `duration` and `waiting` times.
If we collected a different sample of $n$ pairs, the coefficient for the slope would likely be different due to *sampling variation*.
Say we hypothetically collect many random samples of pairs of `duration` and `waiting` times, and using the least-squares method compute the slope $b_1$ for each of these samples.
These slopes would form the sampling distribution of $b_1$, which we discussed in @sec-sampling-variation in the context of sample proportions.
What we would learn is that, because $y_1, \dots, y_n$ are normally distributed and $b_1$ is a linear combination of these random variables, $b_1$ is also normally distributed.
After some calculations that go beyond the scope of this book but take into account properties of the expected value and standard deviation of the responses $y_1, \dots, y_n$, it can be shown that:
$$b_1 \sim Normal \left(\beta_1\,,\, \frac{\sigma}{\sqrt{\sum_{i=1}^n(x_i - \bar x)^2}}\right)$$
That is, $b_1$ is normally distributed with expected value $\beta_1$ and standard deviation equal to the expression above (inside the parentheses and after the comma).
Similarly, $b_0$ is a linear combination of $y_1, \dots, y_n$ and using properties of the expected value and standard deviation of the responses, we get:
$$b_0 \sim Normal \left(\beta_0\,,\, \sigma\sqrt{\frac1n + \frac{\bar x^2}{\sum_{i=1}^n(x_i - \bar x)^2}}\right)$$
We can also standardize the least-square estimators such that
$$z_0 = \frac{b_0 - \beta_0}{\left(\sigma\sqrt{\frac1n + \frac{\bar x^2}{\sum_{i=1}^n(x_i - \bar x)^2}}\right)}\qquad\text{ and }\qquad z_1 = \frac{b_1 - \beta_1}{\left(\frac{\sigma}{\sqrt{\sum_{i=1}^n(x_i - \bar x)^2}}\right)}$$
are the corresponding standard normal distributions.
### Standard errors for least-squares estimators {#sec-se-simple-lm}
Recall that in @sec-sampling and in @sec-CLT-mean we discussed that, due to the Central Limit Theorem, the distribution of the sample mean $\overline X$ was approximately normal with mean equal to the parameter $\mu$ and standard deviation equal to $\sigma/\sqrt n$.
We then used the estimated standard error of $\overline X$ to construct confidence intervals and hypothesis tests.
An analogous treatment is now used to construct confidence intervals and hypothesis tests for $b_0$ and $b_1$.
Observe in the equations above that the standard deviations for $b_0$ and $b_1$ are constructed using the sample size $n$, the values of the explanatory variables, their means, and the standard deviation of $y_i$ ($\sigma$).
While most of these values are known to us, $\sigma$ is typically not.
Instead, we estimate $\sigma$ using the estimator of the standard deviation, $s$, introduced in @sec-least-squares.
The estimated standard deviation of $b_1$ is called the *standard error* of $b_1$, and it is given by:
$$SE(b_1) = \frac{s}{\sqrt{\sum_{i=1}^n(x_i - \bar x)^2}}.$$
Recall that the *standard error* is the standard deviation of any point estimate computed from a sample.
The *standard error* of $b_1$ quantifies how much variation the estimator of the slope $b_1$ may have for different random samples.
The larger the standard error, the more variation we would expect in the estimated slope $b_1$.
Similarly, the *standard error* of $b_0$ is:
$$SE(b_0) = s\sqrt{\frac1n + \frac{\bar x^2}{\sum_{i=1}^n(x_i - \bar x)^2}}$$
As was discussed in @sec-t-distribution-CI, when using the estimator $s$ instead of the parameter $\sigma$, we are introducing additional uncertainty in our calculations.
For example, we can standardize $b_1$ using
$$t = \frac{b_1 - \beta_1}{SE(b_1)}.$$
Because we are using $s$ to calculate $SE(b_1)$, the value of the standard error changes from sample to sample, and this additional uncertainty makes the distribution of the test statistic $t$ no longer normal.
Instead, it follows a $t$-distribution with $n-2$ degrees of freedom.
The loss of two degrees of freedom relates to the fact that we are trying to estimate two parameters in the linear model: $\beta_0$ and $\beta_1$. We are ready to use this information to perform inference for the least-square estimators, $b_0$ and $b_1$.
### Confidence intervals for the least-squares estimators {#sec-conf-intervals-b0-b1}
A 95% confidence interval for $\beta_1$ can be thought of as a range of plausible values for the population slope $\beta_1$ of the linear relationship between `duration` and `waiting` times.
In general, if the sampling distribution of an estimator is normal or approximately normal, the confidence interval for the relevant parameter is
$$
\text{point estimate} \pm \text{margin of error} = \text{point estimate} \pm (\text{critical value} \cdot \text{standard error}).
$$
The formula for a 95% confidence interval for $\beta_1$ is given by $b_1 \pm q \cdot SE(b_1)$ where the critical value $q$ is determined by the level of confidence required, the sample size used, and the corresponding degrees of freedom needed for the $t$-distribution.
We now illustrate how to find the 95% confidence interval for the slope in the Old Faithful example manually, but we show later how to do this directly in R using the function [`get_regression_table()`](https://moderndive.github.io/moderndive/reference/get_regression_table.html).
First, observe that $n = `r n_old_faithful`$, so the degrees of freedom are $n-2 = 112$. The critical value for a 95% confidence interval on a $t$-distribution with 112 degrees of freedom is $q = 1.981$. Second, the estimates $b_0$, $b_1$, and $s$ were found earlier and are shown here again in @tbl-regtable-ch10-2:
```{r tbl-regtable-ch10-2, echo=FALSE, purl=FALSE}
# Fit regression model:
model_1 <- lm(waiting ~ duration, data = old_faithful_2024)
b_coef <- round(coef(model_1),2)
# Get the coefficients of the model
lm_data <- data.frame("Coefficients" = c("b0", "b1", "s"),"Values" = c(coefficients(model_1),sigma(model_1)))
lm_data |>
kbl(
digits = 3,
caption = "Old Faithful linear regression coefficients",
booktabs = TRUE,
linesep = ""
) |>
kable_styling(
font_size = ifelse(is_latex_output(), 10, 16),
latex_options = c("HOLD_position")
)
```
Third, the standard error for $b_1$ using the formula presented earlier is:
```{r inference-for-regression-dynamic-text-alt, echo=FALSE}
# This code is used for dynamic non-static in-line text output purposes
q = round(qt(p = (1 - (1-0.95)/2), df = 114 - 2),3)
s <- round(sigma(model_1),3)
x <- old_faithful_2024$duration
n_old_faithful <- length(x)
#beta1
b1 <- round(coef(model_1)[[2]],3)
denom_se_b1 <- round(sqrt(sum((x - mean(x))^2)),3)
se_b1 <- round(s/denom_se_b1,3)
lb1 <- round(b1 - q*se_b1,3)
ub1 <- round(b1 + q*se_b1,3)
# beta0
b0 <- round(coef(model_1)[[1]],3)
se_b0 <- round(s*sqrt(1/n_old_faithful + mean(x)^2/sum((x - mean(x))^2)),3)
lb0 <- round(b0 - q*se_b0,3)
ub0 <- round(b0 + q*se_b0,3)
# t
t_stat <- round(b1/se_b1,3)
p_value <- round(2*(1 - pt(abs(t_stat), n_old_faithful-2)), 3)
```
$$SE(b_1) = \frac{s}{\sqrt{\sum_{i=1}^n(x_i - \bar x)^2}} = \frac{`r s`}{`r denom_se_b1`} = `r se_b1`.$$
Finally, the 95% confidence interval for $\beta_1$ is given by:
$$\begin{aligned}
b_1 &\pm q \cdot SE(b_1)\\
&= `r b1` \pm `r q`\cdot `r se_b1`\\
&= (`r lb1` , `r ub1`)
\end{aligned}$$
We are 95% confident that the population slope $\beta_1$ is a number between `r lb1` and `r ub1`.
The construction of a 95% confidence interval for $\beta_0$ follows exactly the same steps using $b_0$, $SE(b_0)$, and the same critical value $q$ as the degrees of freedom for the $t$-distribution are exactly the same, $n-2$:
$$\begin{aligned}
b_0 &\pm q \cdot SE(b_0)\\
&= `r b0` \pm `r q`\cdot `r se_b0`\\
&= (`r lb0`, `r ub0`)
\end{aligned}$$
The results of the confidence intervals are valid only if the linear model assumptions are satisfied.
We discuss these assumptions in @sec-model-fit.
### Hypothesis test for population slope {#sec-hypo-test-simple-lm}
To perform a hypothesis test for $\beta_1$, the general formulation of a two-sided test is
$$\begin{aligned}
H_0: \beta_1 = B\\
H_A: \beta_1 \ne B
\end{aligned}$$
where $B$ is the hypothesized value for $\beta_1$. Recall the terminology, notation, and definitions related to hypothesis tests we introduced in @sec-understanding-ht.
A *hypothesis test* consists of a test between two competing hypotheses: (1) a *null hypothesis* $H_0$ versus (2) an *alternative hypothesis* $H_A$.
#### Test statistic {#sec-t-test-stat-simple-lm .unnumbered}
A *test statistic* is a point estimator used for hypothesis testing. Here, the *t-test statistic* is given by
$$t = \frac{b_1 - B}{SE(b_1)}.$$
This test statistic follows, under the null hypothesis, a $t$-distribution with $n-2$ degrees of freedom.
A particularly useful test is whether there is a linear association between the explanatory variable and the response, which is equivalent to testing:
$$\begin{aligned}
H_0: \beta_1 = 0\\
H_A: \beta_1 \ne 0
\end{aligned}$$
For example, we may use this test to determine whether there is a linear relationship between the duration of the Old Faithful geyser eruptions (`duration`) and the waiting time to the next eruption (`waiting`).
The *null hypothesis* $H_0$ assumes that the population slope $\beta_1$ is 0.
If this is true, then there is *no linear relationship* between the `duration` and `waiting` times.
When performing a hypothesis test, we assume that the null hypothesis $H_0: \beta_1 = 0$ is true and try to find evidence against it based on the data observed.
The *alternative hypothesis* $H_A$, on the other hand, states that the population slope $\beta_1$ is not 0, meaning that longer eruption `duration` may result in greater or smaller `waiting` times to the next eruption.
This suggests either a positive or negative linear relationship between the explanatory variable and the response.
Since evidence against the null hypothesis may happen in either direction in this context, we call this a *two-sided* test.
The *t-test* statistic for this problem is given by:
$$t = \frac{b_1 - 0}{SE(b_1)} = \frac{`r b1` - 0}{`r se_b1`} = `r t_stat`$$
#### The p-value {.unnumbered}
Recall the terminology, notation, and definitions related to hypothesis tests we introduced in @sec-understanding-ht.
The definition of the $p$-value is the probability of obtaining a test statistic just as extreme as or more extreme than the one observed, *assuming the null hypothesis* $H_0$ is true.
We can intuitively think of the $p$-value as quantifying how "extreme" the estimated slope is ($b_1$ = `r b1`), assuming there is no relationship between `duration` and `waiting` times.
For a two-sided test, if the test statistic is $t = 2$ for example, the $p$-value is calculated as the area under the $t$-curve to the left of $-2$ and to the right of $2$ is shown in @fig-pvalue1.
```{r fig-pvalue1, fig.alt="Standard t-curve with both tails shaded beyond the observed t-statistic, visualizing a two-sided p-value.", echo=FALSE, fig.height=ifelse(knitr::is_latex_output(), 2, 4), fig.cap="Illustration of a two-sided p-value for a t-test."}
n <- n_old_faithful
shade <- function(t, a,b) {
z = dt(t, df = n-2)
z[abs(t) < b & -abs(t)>a] <- NA
return(z)
}
ggplot(data.frame(x = c(-4, 4)), aes(x = x)) +
stat_function(fun = dt, args = list(df = n-2)) +
stat_function(fun = shade, args = list(a = -2, b = 2),
geom = "area", fill = "blue", alpha = .2)+
scale_x_continuous(name = "t", breaks = seq(-4, 4, 2))+
scale_y_continuous(labels = NULL)+
theme(axis.title.y = element_blank(), axis.ticks.y = element_blank())
```
In our Old Faithful geyser eruptions example, the test statistic for the test $H_0: \beta_1 = 0$ was $t = `r t_stat`$.
The $p$-value was so small that R simply shows that it is equal to zero.
#### Interpretation {.unnumbered}
Following the hypothesis testing procedure we outlined in @sec-ht-interpretation, since the $p$-value was practically 0, for any choice of significance level $\alpha$, we would reject $H_0$ in favor of $H_A$.
In other words, assuming that there is no linear association between `duration` and `waiting` times, the probability of observing a slope as extreme as the one we have attained using our random sample, was practically zero.
In conclusion, we reject the null hypothesis that there is no linear relationship between `duration` and `waiting` times.
We have enough statistical evidence to conclude that there is a linear relationship between these variables.
::: {.learncheck}
**Learning Check**
**`r paste0("(LC", chap, ".", (lc <- lc + 1), ")")`** In the context of a linear regression model, what does the null hypothesis $H_0: \beta_1 = 0$ represent?
- A. There is no linear association between the response and the explanatory variable.
- B. The difference between the observed and predicted values is zero.
- C. The linear association between response and explanatory variable crosses the origin.
- D. The probability of committing a Type II Error is zero.
<!-- question above was repeated. I changed it -->
```{r lc-sol-10-04, echo=FALSE, results='asis', purl=FALSE}
cat(lc_solution(10, 4))
```
**`r paste0("(LC", chap, ".", (lc <- lc + 1), ")")`** Which of the following is an assumption of the linear regression model?
- A. The error terms $\epsilon_i$ are normally distributed with constant variance.
- B. The error terms $\epsilon_i$ have a non-zero mean.
- C. The error terms $\epsilon_i$ are dependent on each other.
- D. The explanatory variable must be normally distributed.
```{r lc-sol-10-05, echo=FALSE, results='asis', purl=FALSE}
cat(lc_solution(10, 5))
```
**`r paste0("(LC", chap, ".", (lc <- lc + 1), ")")`** What does it mean when we say that the slope estimator $b_1$ is a random variable?
- A. $b_1$ will be the same for every sample taken from the population.
- B. $b_1$ is a fixed value that does not change with different samples.
- C. $b_1$ can vary from sample to sample due to sampling variation.
- D. $b_1$ is always equal to the population slope $\beta_1$.
```{r lc-sol-10-06, echo=FALSE, results='asis', purl=FALSE}
cat(lc_solution(10, 6))
```
:::
### The regression table in R {#sec-regression-table}
The least-square estimates, standard errors, test statistics, $p$-values, and confidence interval bounds discussed in @sec-theory-simple-regression and @sec-framework-simple-lm, @sec-se-simple-lm, @sec-conf-intervals-b0-b1, and @sec-hypo-test-simple-lm can be calculated, all at once, using the R wrapper function [`get_regression_table()`](https://moderndive.github.io/moderndive/reference/get_regression_table.html) from the `moderndive` package.
For `model_1`, the output is presented in @tbl-simple-model-part-deux.
```{r inference-for-regression-reg-table, eval=FALSE}
get_regression_table(model_1)
```
```{r tbl-simple-model-part-deux, echo=FALSE, purl=FALSE}
get_regression_table(model_1) |>
kbl(
caption = "The regression table for this model",
digits = 3,
booktabs = TRUE,
linesep = ""
) |>
kable_styling(
font_size = ifelse(is_latex_output(), 9, 16),
latex_options = c("HOLD_position")
)
```
Note that the first row in @tbl-simple-model-part-deux addresses inferences for the intercept $\beta_0$, and the second row deals with inference for the slope $\beta_1$.
The headers of the table present the information found for inference:
- The `estimate` column contains the least-squares estimates, $b_0$ (first row) and $b_1$ (second row).
- The `std_error` contains $SE(b_0)$ and $SE(b_1)$ (the standard errors for $b_0$ and $b_1$), respectively.
We defined these standard errors in @sec-se-simple-lm.
- The `statistic` column contains the $t$-test statistic for $b_0$ (first row) and $b_1$ (second row).
If we focus on $b_1$, the $t$-test statistic was constructed using the equation
$$
t = \frac{b_1 - 0}{SE(b_1)} = `r t_stat`
$$
which corresponds to the hypotheses $H_0: \beta_1 = 0$ versus $H_A: \beta_1 \ne 0$.
- The `p_value` is the probability of obtaining a test statistic just as extreme as or more extreme than the one observed, assuming the null hypothesis is true.
For this hypothesis test, the $t$-test statistic was equal to `r t_stat` and, therefore, the $p$-value was near zero, suggesting rejection of the null hypothesis in favor of the alternative.
- The values `lower_ci` and `upper_ci` are the lower and upper bounds of a 95% confidence interval for $\beta_1$.
Please refer to previous subsections for the conceptual framework and a more detailed description of these quantities.
### Model fit and model assumptions {#sec-model-fit}
We have introduced the linear model alongside assumptions about many of its elements and assumed all along that this is an appropriate representation of the relationship between the response and the explanatory variable.
In real-life applications, it is uncertain whether the relationship is appropriately described by the linear model or whether all the assumptions we have introduced are satisfied.
Of course, we do not expect the linear model described in this chapter, or any other model, to be a perfect representation of a phenomenon presented in nature.
Models are simplifications of reality in that they do not intend to represent exactly the relationship in question but rather provide useful approximations that help improve our understanding of this relationship.
Even more, we want models that are as simple as possible and still capture relevant features of the natural phenomenon we are studying.
This approach is known as the *principle of parsimony* or *Occam's razor*.
But even with a simple model like a linear one, we still want to know if it accurately represents the relationship in the data.
This is called *model fit*.
In addition, we want to determine whether or not the model assumptions have been met.
There are four elements in the linear model we want to check.
An acrostic is a composition in which certain letters from each piece form a word or words.
To help you remember the four elements, we can use the following acrostic:
1. **L**inearity of relationship between variables
- Is the relationship between $y_i$ and $x_i$ truly linear for each $i = 1, \dots, n$?
In other words, is the linear model $y_i = \beta_0 + \beta_1 \cdot x_i + \epsilon_i$ a good fit?
2. **I**ndependence of each of the response values $y_i$
- Are $y_i$ and $y_j$ independent for any $i \ne j$?
3. **N**ormality of the error terms
- Is the distribution of the error terms at least approximately normal?
4. **E**quality or constancy of the variance for $y_i$ (and for the error term $\epsilon_i$)
- Is the variance, or equivalently standard deviation, of the response $y_i$ always the same, regardless of the fitted value ($\widehat{y}_i$) or the regressor value ($x_i$)?
In this case, our acrostic follows the word **LINE**.
This can serve as a nice reminder of what to check when using linear regression\index{regression!model fit (LINE)}.
To check for **L**inearity, **N**ormality, and **E**qual or constant variance, we use the residuals of the linear regression via *residual diagnostics*\index{residual analysis} as we explain in the next subsection.
To check for **I**ndependence we can use the residuals if the data was collected using a time sequence or other type of sequences.
Otherwise, independence may be achieved by taking a random sample, which eliminates a sequential type of dependency.
We start by reviewing how residuals are calculated, introduce residual diagnostics via visualizations, use the example of the Old Faithful geyser eruptions to determine whether each of the four **LINE** elements are met, and discuss the implications.
#### Residuals {.unnumbered}
Recall that given a random sample of $n$ pairs $(x_1, y_1), \dots, (x_n,y_n)$ the linear regression was given by:
$$\widehat{y}_i = b_0 + b_1 \cdot x_i$$
for all the observations $i = 1, \dots, n$.
Recall that the residual as defined in @sec-model1points, is the *observed response* minus the *fitted value*.
If we denote the residuals with the letter $e$ we get:
$$e_i = y_i - \widehat{y}_i$$
for $i = 1, \dots, n$.
Combining these two formulas we get
$$y_i = \underline{\widehat{y}_i} + e_i = \underline{b_0 + b_1 \cdot x_i} + e_i$$
the resulting formula looks very similar to our linear model:
$$y_i = \beta_0 + \beta_1 \cdot x_i + \epsilon_i$$
In this context, residuals can be thought of as rough estimates of the error terms.
Since many of the assumptions of the linear model are related to the error terms, we can check these assumptions by studying the residuals.
In @fig-residual-example, we illustrate one particular residual for the Old Faithful geyser eruption where `duration` time is the explanatory variable and `waiting` time is the response.
We use an arrow to connect the observed waiting time (a circle) with the fitted waiting time (a square).
The vertical distance between these two points (or equivalently, the magnitude of the arrow) is the value of the residual for this observation.
```{r fig-residual-example, fig.alt="Annotated scatterplot showing one observed point, its fitted value on the regression line, and the residual segment between them.", echo=FALSE, fig.cap="Example of observed value, fitted value, and residual.", purl=FALSE, message=FALSE, fig.height=ifelse(knitr::is_latex_output(), 2.2, 4)}
# Pick out one particular point to drill down on
index <- which(old_faithful_2024$duration == 211 & old_faithful_2024$waiting == 178)
target_point <- model_1 |>
get_regression_points() |>
slice(index)
x <- target_point$duration
y <- target_point$waiting
y_hat <- target_point$waiting_hat
resid <- target_point$residual
# Plot residual