
Lecturer: Michael Lydeamore
Department of Econometrics and Business Statistics
Aim
Why

🎯 Characterise mpg in terms of wt.
We fit the model:
\[\texttt{mpg}_i = \beta_0 + \beta_1\texttt{wt}_i + e_i\]
fit?fit even contain?List of 12
$ coefficients : Named num [1:2] 37.29 -5.34
..- attr(*, "names")= chr [1:2] "(Intercept)" "wt"
$ residuals : Named num [1:32] -2.28 -0.92 -2.09 1.3 -0.2 ...
..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
$ effects : Named num [1:32] -113.65 -29.116 -1.661 1.631 0.111 ...
..- attr(*, "names")= chr [1:32] "(Intercept)" "wt" "" "" ...
$ rank : int 2
$ fitted.values: Named num [1:32] 23.3 21.9 24.9 20.1 18.9 ...
..- attr(*, "names")= chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
$ assign : int [1:2] 0 1
$ qr :List of 5
..$ qr : num [1:32, 1:2] -5.657 0.177 0.177 0.177 0.177 ...
.. ..- attr(*, "dimnames")=List of 2
.. .. ..$ : chr [1:32] "Mazda RX4" "Mazda RX4 Wag" "Datsun 710" "Hornet 4 Drive" ...
.. .. ..$ : chr [1:2] "(Intercept)" "wt"
.. ..- attr(*, "assign")= int [1:2] 0 1
..$ qraux: num [1:2] 1.18 1.05
..$ pivot: int [1:2] 1 2
..$ tol : num 1e-07
..$ rank : int 2
..- attr(*, "class")= chr "qr"
$ df.residual : int 30
$ xlevels : Named list()
$ call : language lm(formula = mpg ~ wt, data = mtcars)
$ terms :Classes 'terms', 'formula' language mpg ~ wt
.. ..- attr(*, "variables")= language list(mpg, wt)
.. ..- attr(*, "factors")= int [1:2, 1] 0 1
.. .. ..- attr(*, "dimnames")=List of 2
.. .. .. ..$ : chr [1:2] "mpg" "wt"
.. .. .. ..$ : chr "wt"
.. ..- attr(*, "term.labels")= chr "wt"
.. ..- attr(*, "order")= int 1
.. ..- attr(*, "intercept")= int 1
.. ..- attr(*, "response")= int 1
.. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
.. ..- attr(*, "predvars")= language list(mpg, wt)
.. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
.. .. ..- attr(*, "names")= chr [1:2] "mpg" "wt"
$ model :'data.frame': 32 obs. of 2 variables:
..$ mpg: num [1:32] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
..$ wt : num [1:32] 2.62 2.88 2.32 3.21 3.44 ...
..- attr(*, "terms")=Classes 'terms', 'formula' language mpg ~ wt
.. .. ..- attr(*, "variables")= language list(mpg, wt)
.. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
.. .. .. ..- attr(*, "dimnames")=List of 2
.. .. .. .. ..$ : chr [1:2] "mpg" "wt"
.. .. .. .. ..$ : chr "wt"
.. .. ..- attr(*, "term.labels")= chr "wt"
.. .. ..- attr(*, "order")= int 1
.. .. ..- attr(*, "intercept")= int 1
.. .. ..- attr(*, "response")= int 1
.. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv>
.. .. ..- attr(*, "predvars")= language list(mpg, wt)
.. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
.. .. .. ..- attr(*, "names")= chr [1:2] "mpg" "wt"
- attr(*, "class")= chr "lm"
Use accessor functions to retrieve model results:
This gives us the estimates of \(\beta_0\) and \(\beta_1\).
An estimate is more useful when accompanied by its uncertainty:
You can also get a summary of the model object:
Call:
lm(formula = mpg ~ wt, data = mtcars)
Residuals:
Min 1Q Median 3Q Max
-4.5432 -2.3647 -0.1252 1.4096 6.8727
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 37.2851 1.8776 19.858 < 2e-16 ***
wt -5.3445 0.5591 -9.559 1.29e-10 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 3.046 on 30 degrees of freedom
Multiple R-squared: 0.7528, Adjusted R-squared: 0.7446
F-statistic: 91.38 on 1 and 30 DF, p-value: 1.294e-10
The printed summary is useful for inspection, but it is not an audience-ready result.
# A tibble: 2 × 5
term estimate std.error statistic p.value
<chr> <dbl> <dbl> <dbl> <dbl>
1 (Intercept) 37.3 1.88 19.9 8.24e-19
2 wt -5.34 0.559 -9.56 1.29e-10
# A tibble: 32 × 9
.rownames mpg wt .fitted .resid .hat .sigma .cooksd .std.resid
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Mazda RX4 21 2.62 23.3 -2.28 0.0433 3.07 1.33e-2 -0.766
2 Mazda RX4 Wag 21 2.88 21.9 -0.920 0.0352 3.09 1.72e-3 -0.307
3 Datsun 710 22.8 2.32 24.9 -2.09 0.0584 3.07 1.54e-2 -0.706
4 Hornet 4 Drive 21.4 3.22 20.1 1.30 0.0313 3.09 3.02e-3 0.433
5 Hornet Sportabout 18.7 3.44 18.9 -0.200 0.0329 3.10 7.60e-5 -0.0668
6 Valiant 18.1 3.46 18.8 -0.693 0.0332 3.10 9.21e-4 -0.231
7 Duster 360 14.3 3.57 18.2 -3.91 0.0354 3.01 3.13e-2 -1.31
8 Merc 240D 24.4 3.19 20.2 4.16 0.0313 3.00 3.11e-2 1.39
9 Merc 230 22.8 3.15 20.5 2.35 0.0314 3.07 9.96e-3 0.784
10 Merc 280 19.2 3.44 18.9 0.300 0.0329 3.10 1.71e-4 0.100
# ℹ 22 more rows
broom verb answers a different question| Verb | Unit of output | Use it to find… |
|---|---|---|
tidy(fit) |
one row per model term | estimates, standard errors and uncertainty |
glance(fit) |
one row per model | model-level summaries such as \(R^2\), AIC and sample size |
augment(fit) |
one row per observation | fitted values, residuals and influence measures |
The same interface works across many model classes. broom selects the appropriate method from the class of the fitted object.
# A tibble: 2 × 7
term estimate std.error statistic p.value conf.low conf.high
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 (Intercept) 37.3 1.88 19.9 8.24e-19 33.5 41.1
2 wt -5.34 0.559 -9.56 1.29e-10 -6.49 -4.20
The tidy output is data. We can now select, rename and present the results without copying values from the printed model summary.
| Characteristic | Beta | 95% CI | p-value |
|---|---|---|---|
| (Intercept) | 37 | 33, 41 | <0.001 |
| wt | -5.3 | -6.5, -4.2 | <0.001 |
| Abbreviation: CI = Confidence Interval | |||
Imagine this table will go to a technically competent, time-poor manager.
| Characteristic | Beta | 95% CI |
|---|---|---|
| Weight (1,000 lb) | -5.3 | -6.5, -4.2 |
| Abbreviation: CI = Confidence Interval | ||
Important
Each additional 1,000 lb of vehicle weight is associated with 5.34 fewer mpg, on average (95% confidence interval: 4.2 to 6.49 fewer mpg).
Start with the communication question, not with everything the model produced.
summary_table <- mtcars |>
mutate(cyl = factor(cyl)) |>
select(mpg, wt, cyl) |>
gtsummary::tbl_summary(
by = cyl,
label = list(
mpg ~ "Fuel economy (mpg)",
wt ~ "Weight (1,000 lb)"
),
statistic = gtsummary::all_continuous() ~ "{mean} ({sd})",
digits = gtsummary::all_continuous() ~ 1,
missing = "no"
) |>
gtsummary::bold_labels()
summary_table| Characteristic | 4 N = 111 |
6 N = 71 |
8 N = 141 |
|---|---|---|---|
| Fuel economy (mpg) | 26.7 (4.5) | 19.7 (1.5) | 15.1 (2.6) |
| Weight (1,000 lb) | 2.3 (0.6) | 3.1 (0.4) | 4.0 (0.8) |
| 1 Mean (SD) | |||
| name | Mean | SD | 1. | 2. |
|---|---|---|---|---|
| mpg | 20.09062 | 6.0269481 | ||
| wt | 3.21725 | 0.9784574 | -0.8676594 | |
| hp | 146.68750 | 68.5628685 | -0.7761684 | 0.6587479 |
options(knitr.kable.NA = '')
mtcars |>
select(mpg, wt, hp) |>
pivot_longer(everything()) |>
mutate(name = factor(name, levels = c("mpg", "wt", "hp"))) |>
group_by(name) |>
summarise(
Mean = mean(value),
SD = sd(value)
) |>
mutate(
`1.` = case_when(
name == "wt" ~ cor(mtcars$mpg, mtcars$wt),
name == "hp" ~ cor(mtcars$mpg, mtcars$hp),
TRUE ~ NA_real_
),
`2.` = case_when(
name == "hp" ~ cor(mtcars$wt, mtcars$hp),
TRUE ~ NA_real_
)
) |>
knitr::kable(table.attr = "class='cor-table'") |>
kable_classic(full_width = FALSE)| cyl/gear | 3 | 4 | 5 | Total |
|---|---|---|---|---|
| 4 | 3.1% (1) | 25.0% (8) | 6.2% (2) | 34.4% (11) |
| 6 | 6.2% (2) | 12.5% (4) | 3.1% (1) | 21.9% (7) |
| 8 | 37.5% (12) | 0.0% (0) | 6.2% (2) | 43.8% (14) |
| Total | 46.9% (15) | 37.5% (12) | 15.6% (5) | 100.0% (32) |
library(janitor)
mtcars |>
tabyl(cyl, gear) |>
adorn_totals(where = c("row", "col")) |>
adorn_percentages("all") |>
adorn_pct_formatting(digits = 1) |>
adorn_ns() |>
adorn_title("combined") |>
knitr::kable(table.attr = "class='xtab'") |>
kable_styling() |>
row_spec(4, extra_css = "border-top: 1px solid black;") |>
kable_classic(full_width = FALSE)
Weight
|
|||
|---|---|---|---|
| Car brand | 5 d.p. | 2 d.p. | 0 d.p. |
| Mazda RX4 | 2.61937 | 2.62 | 3 |
| Mazda RX4 Wag | 2.87518 | 2.88 | 3 |
| Datsun 710 | 2.31916 | 2.32 | 2 |
| Hornet 4 Drive | 3.21660 | 3.21 | 3 |
Trailing zeroes
|
|
|---|---|
| Yes | No |
| 0.233 | 0.233 |
| 0.320 | 0.32 |
| 0.400 | 0.4 |
| 0.343 | 0.343 |
| Car brand | Weight (lb) | Weight (1,000 lb) | Weight (kg) | Weight (g) | Weight (mg) |
|---|---|---|---|---|---|
| Mazda RX4 | 2620 | 2.620 | 1188 | 1190000 | 1,188,000,000 |
| Mazda RX4 Wag | 2875 | 2.875 | 1304 | 1300000 | 1,304,000,000 |
| Datsun 710 | 2320 | 2.320 | 1052 | 1050000 | 1,052,000,000 |
| Hornet 4 Drive | 3215 | 3.215 | 1458 | 1460000 | 1,458,000,000 |
1,000,000 is easier to read than 1000000 for an Australian audience.
Car brand
|
Horsepower
|
||||
|---|---|---|---|---|---|
| Left | Center | Right | Left | Center | Right |
| Mazda RX4 | Mazda RX4 | Mazda RX4 | 110 | 110 | 110 |
| Mazda RX4 Wag | Mazda RX4 Wag | Mazda RX4 Wag | 110 | 110 | 110 |
| Datsun 710 | Datsun 710 | Datsun 710 | 93 | 93 | 93 |
| Hornet 4 Drive | Hornet 4 Drive | Hornet 4 Drive | 110 | 110 | 110 |
| car | wt | disp |
|---|---|---|
| Mazda RX4 | 2620 lb | 160 cubic inches |
| Mazda RX4 Wag | 2875 lb | 160 cubic inches |
| Datsun 710 | 2320 lb | 108 cubic inches |
| Hornet 4 Drive | 3215 lb | 258 cubic inches |
| Hornet Sportabout | 3440 lb | 360 cubic inches |
| Valiant | 3460 lb | 225 cubic inches |
| Car brand | Weight (1,000 lb) | Displacement (cubic inches) |
|---|---|---|
| Mazda RX4 | 2.620 | 160 |
| Mazda RX4 Wag | 2.875 | 160 |
| Datsun 710 | 2.320 | 108 |
| Hornet 4 Drive | 3.215 | 258 |
| Hornet Sportabout | 3.440 | 360 |
| Valiant | 3.460 | 225 |
Summary
broom to turn a fitted model into data you can work with.gtsummary to create a table, then refine its precision, alignment and labels.
ETC5523 Week 5A