Functions described below:
create_lm_table()
/ source codecreate_lm_summary()
/ source codeThese functions create a publication-ready table summarizing a linear model fit. Use these functions if you have fit a linear model in R using the lm
function and would like to compile the results into a concise set of metrics. To illustrate how to use these functions, I will use data from the iris
dataset that comes built-in with R:
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
These functions have a few dependencies, which I load below:
Consider the case of a simple multiple linear regression analysis. For the iris
dataset, I examine whether petal length and/or petal width are associated with sepal length:
The call to create-lm-table()
below generates a dataframe displaying the coefficients, their standard errors and confidence intervals, and associated t- and p-values. The first argument is the output of the call to the lm
function. The second argument include.intercept = 1
is included to indicate that I would like a row indicating these values for the intercept term. The third argument vector.of.term.names
allows me to customize the names of the terms that will be displayed in the first column of the dataframe
create_lm_table(lm.object = lm.overall,
include.intercept = 1,
vector.of.term.names = c('Intercept', 'Petal Length', 'Petal Width'))
## Predictor Beta SE 95% CI t p
## 1 Intercept 4.191 0.097 4.382, 3.999 43.18 <.001
## 2 Petal Length 0.542 0.069 0.679, 0.405 7.82 <.001
## 3 Petal Width -0.32 0.16 -0.002, -0.637 -1.99 .048
The call to create-lm-summary()
below generates a string summarizing the fit of the regression model, specifically the \(R^2\) and adjusted \(R^2\) values, and the F statistic for the model fit as well as its degrees of freedom. This function takes only one argument, the output of the call to the lm
function:
## [1] "F(2, 147) = 240.95, p < .001, R^2 = 0.766, adjusted R^2 = 0.763"
Finally, I use the kableExtra
package to combine these outputs into a single, publication-ready table:
library(kableExtra)
table_overall <- create_lm_table(lm.object = lm.overall,
include.intercept = 1,
vector.of.term.names = c('Intercept', 'Petal Length', 'Petal Width'))
kable(table_overall) %>%
kable_styling(full_width = F,
'striped',
position = 'left') %>%
pack_rows(str_c(create_lm_summary(lm.object = lm.overall)),
1, nrow(table_overall))
Predictor | Beta | SE | 95% CI | t | p |
---|---|---|---|---|---|
F(2, 147) = 240.95, p < .001, R^2 = 0.766, adjusted R^2 = 0.763 | |||||
Intercept | 4.191 | 0.097 | 4.382, 3.999 | 43.18 | <.001 |
Petal Length | 0.542 | 0.069 | 0.679, 0.405 | 7.82 | <.001 |
Petal Width | -0.32 | 0.16 | -0.002, -0.637 | -1.99 | .048 |
Next, I consider the case of a regression analysis with multiple groups, where I might want to create a table in which coefficients, etc. for each group are stacked on top of one another. I use the iris
dataset again, this time performing a separate regression of petal length and width on sepal length, for each iris species separately:
lm.setosa <- lm(Sepal.Length ~ Petal.Length + Petal.Width, data = iris %>% filter(Species == 'setosa'))
lm.versicolor <- lm(Sepal.Length ~ Petal.Length + Petal.Width, data = iris %>% filter(Species == 'versicolor'))
lm.virginica <- lm(Sepal.Length ~ Petal.Length + Petal.Width, data = iris %>% filter(Species == 'virginica'))
I consolidate the steps above to create a single, composite table summarizing the output of all three model fits:
table_setosa <- create_lm_table(lm.object = lm.setosa,
include.intercept = 1,
vector.of.term.names = c('Intercept', 'Petal Length', 'Petal Width'))
table_versicolor <- create_lm_table(lm.object = lm.versicolor,
include.intercept = 1,
vector.of.term.names = c('Intercept', 'Petal Length', 'Petal Width'))
table_virginica <- create_lm_table(lm.object = lm.virginica,
include.intercept = 1,
vector.of.term.names = c('Intercept', 'Petal Length', 'Petal Width'))
kable(as.data.frame(rbind(table_setosa,
table_versicolor,
table_virginica))) %>%
kable_styling(full_width = F, 'striped', position = 'left') %>%
pack_rows(str_c('Setosa, ', create_lm_summary(lm.object = lm.setosa), sep = ''), 1, nrow(table_setosa)) %>%
pack_rows(str_c('Versicolor, ', create_lm_summary(lm.object = lm.versicolor), sep = ''), nrow(table_setosa)+1, nrow(table_setosa)+nrow(table_versicolor)) %>%
pack_rows(str_c('Virginica, ', create_lm_summary(lm.object = lm.virginica), sep = ''), nrow(table_setosa)+nrow(table_versicolor)+1, nrow(table_setosa)+nrow(table_versicolor)+nrow(table_virginica))
Predictor | Beta | SE | 95% CI | t | p |
---|---|---|---|---|---|
Setosa, F(2, 47) = 2.96, p = , R^2 = 0.112, adjusted R^2 = 0.074 | |||||
Intercept | 4.248 | 0.411 | 5.075, 3.42 | 10.32 | <.001 |
Petal Length | 0.399 | 0.296 | 0.994, -0.196 | 1.35 | .184 |
Petal Width | 0.712 | 0.487 | 1.693, -0.268 | 1.46 | .151 |
Versicolor, F(2, 47) = 31.71, p < .001, R^2 = 0.574, adjusted R^2 = 0.556 | |||||
Intercept | 2.381 | 0.449 | 3.284, 1.477 | 5.3 | <.001 |
Petal Length | 0.934 | 0.169 | 1.275, 0.594 | 5.52 | <.001 |
Petal Width | -0.32 | 0.402 | 0.489, -1.129 | -0.8 | .430 |
Virginica, F(2, 47) = 69.35, p < .001, R^2 = 0.747, adjusted R^2 = 0.736 | |||||
Intercept | 1.052 | 0.514 | 2.085, 0.018 | 2.05 | .046 |
Petal Length | 0.995 | 0.089 | 1.174, 0.815 | 11.14 | <.001 |
Petal Width | 0.007 | 0.179 | 0.368, -0.354 | 0.04 | .969 |