mmtable2 can handle tables with multiple layers of header columns. This is paricularly useful for reporting regression results for multiple specifications of subsamples.
Below is an example using the titanic data set to predict survival using logit/LPM, two specifications and separate models for males and females.
The modeling and data preparation are not our primary concern here, but see the source rmd file of this vignette if you’d like to see the function completes these tasks.
We now produce a data frame that is ready for mmtable2. That is, a data frame with a row for each body cell and a column for each header.
cells <-
bind_rows(
get_model_data(sex_filter = "Female", specification_arg = "(II)", model = "LPM" ),
get_model_data(sex_filter = "Female", specification_arg = "(I)", model = "LPM" ),
get_model_data(sex_filter = "Female", specification_arg = "(II)", model = "Logit" ),
get_model_data(sex_filter = "Female", specification_arg = "(I)", model = "Logit" ),
get_model_data(sex_filter = "Male", specification_arg = "(II)", model = "LPM" ),
get_model_data(sex_filter = "Male", specification_arg = "(I)", model = "LPM" ),
get_model_data(sex_filter = "Male", specification_arg = "(II)", model = "Logit" ),
get_model_data(sex_filter = "Male", specification_arg = "(I)", model = "Logit" )
) %>% filter(term != "Intercept") %>%
mutate(value = str_trim(value))
glimpse(cells)
#> Rows: 76
#> Columns: 8
#> $ term <fct> Age, Passenger class, Passenger class, Age, Passenger cl…
#> $ var <chr> "estimate", "estimate", "estimate", "", "", "", "estimat…
#> $ value <chr> "-0.003", "-0.063", "-0.542***", "(0.002)", "(0.058)", "…
#> $ stat_type <chr> "Marginal effects", "Marginal effects", "Marginal effect…
#> $ var_level <chr> "", "2", "3", "", "2", "3", "1", "1", "", "", "", "", ""…
#> $ model_type <chr> "LPM", "LPM", "LPM", "LPM", "LPM", "LPM", "LPM", "LPM", …
#> $ gender <chr> "Female", "Female", "Female", "Female", "Female", "Femal…
#> $ specification <chr> "(II)", "(II)", "(II)", "(II)", "(II)", "(II)", "(II)", …
And here’s the code to create the final table. Notice the use of
header_merged_cols()
. This ensures top_left headers are not
constrained to a single cell.
cells %>%
mmtable(cells = value) +
header_left_top(var_level) +
header_left_top(term) +
header_left_top(stat_type) +
header_top(specification) +
header_top_left(model_type) +
header_top_left(gender) +
cells_format(cell_predicate = T,
style = list(cell_text(align = "left"))
) +
header_format(header = "all_cols",
style = list(cell_text(align = "center"))
) +
header_format(stat_type,
scope = "table",
style = list(
cell_borders(sides = "top",
weight = px(4),
color = "lightgrey"))
) +
header_merged_cols() +
NULL
Female | Male | |||||||||
LPM | Logit | LPM | Logit | |||||||
(I) | (II) | (I) | (II) | (I) | (II) | (I) | (II) | |||
Marginal effects | Age | 0.004 | -0.003 | 0.004 | -0.003 | -0.003* | -0.007*** | -0.003* | -0.007*** | |
(0.002) | (0.002) | (0.002) | (0.002) | (0.001) | (0.001) | (0.001) | (0.001) | |||
Passenger class | 1 | - | - | - | - | |||||
- | - | - | - | |||||||
2 | -0.063 | -0.050 | -0.320*** | -0.365*** | ||||||
(0.058) | (0.036) | (0.056) | (0.063) | |||||||
3 | -0.542*** | -0.545*** | -0.351*** | -0.384*** | ||||||
(0.057) | (0.055) | (0.049) | (0.057) | |||||||
Model statistics | Observations | 261 | 261 | 261 | 261 | 453 | 453 | 453 | 453 | |
R2 | 0.01 | 0.31 | 0.01 | 0.12 | ||||||
Adjusted R2 | 0.01 | 0.30 | 0.01 | 0.11 | ||||||
Log likelihood | -148.42 | -101.90 | -143.59 | -102.62 | -228.85 | -203.08 | -226.61 | -202.93 | ||
Akaike Inf. Crit. | 302.85 | 213.79 | 291.18 | 213.24 | 463.70 | 416.16 | 457.22 | 413.87 | ||
F statistic | 3.54 | 38.37 | 6.55 | 20.47 |
.