Adding Rows to a panelsummary Table

knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.align = "center",
  fig.height = 4
)

```{js, echo = F} $( document ).ready(function() { $(".lightable-classic").removeClass("table").css("display", "table"); });

This vignette shows how to add rows to `panelsummary` tables. Since `panelsummary::panelsummary` returns `kableExtra` objects, adding rows is impossible using the base function `panelsummary::panelsummary`. This can be a nuisance when you want to include additional statistics to your table. However, the workaround is to use the `panelsummary::panelsummary_raw` function. 

## panelsummary::panelsummary_raw

The `panelsummary::panelsummary_raw` function returns a dataframe that can be  manipulated. The trade-off is that the table will need to be customized using the `kableExtra` package, although some of this customization can be completed using the `panelsummary::clean_raw` function (see example).

## Workflow

If you want to create a table with panels that has additional statistical rows, the workflow will be the following:

* Estimate your models (preferably with the `fixest` package).
* Pass your models into `panelsummary::panelsummary_raw` to get a manipulable dataframe.
* Manipulate the dataframe (preferably with `dplyr::add_row`).
* Use `panelsummary::clean_raw` to return a `kableExtra` object.
* Use `kableExtra::pack_rows` to create panel labels.


## Example: Adding Additional Rows to Each Panel 

To demonstrate how to add a row to each panel of a `panelsummary::panelsummary_raw` table, I will assume that each panel needs one additional row for the wild-cluster-bootstrap p-values of the `cyl` column from the `mtcars` data. While I will not explicitly calculate these (in fact, they will be completely made up), the following steps will show how to complete such task.  

Consider the following models, estimated using the `fixest` package:

```r
library(panelsummary)

## Panel A: mpg dependent variable
mpg_1 <- fixest::feols(mpg ~cyl + disp, data = mtcars)
mpg_2 <- fixest::feols(mpg ~ cyl + am, data = mtcars)

## Panel B: wt dependent variable
wt_1 <- fixest::feols(wt ~ cyl + disp, data = mtcars)
wt_2 <- fixest::feols(wt ~ cyl + am, data = mtcars)

Recall that putting each of these two models in a list will result in multiple specifications per-panel.

## putting each panel's models into a list—one for each panel
panel_a_mpg <- list(mpg_1, mpg_2)
panel_b_wt <- list(wt_1, wt_2)

Now, I will pass these two lists into panelsummary::panelsummary_raw. Note that this function shares many of the same arguments as panelsummary::panelsummary. In the following, I will also use the arguments stars (significance stars), mean_dependent (for dependent variable mean), and gof_omit (to omit $R^2$ statistics):

## creating the dataframe
panelsummary_raw(panel_a_mpg, panel_b_wt,
                 stars = "econ",
                 mean_dependent = T,
                 gof_omit = "^R")

The return value of this output is a dataframe without panel labels. Given that it is a dataframe, you can use dplyr functions to easily manipulate. For instance, I will use the dplyr::add_rows function to add the pseudo wild-cluster-bootstrap p-values to the table:

## adding rows using dplyr::add_row
bootstrap_table <- panelsummary_raw(panel_a_mpg, panel_b_wt,
                 stars = "econ",
                 mean_dependent = T,
                 gof_omit = "R") |> 
  dplyr::add_row(term = "Wild Cluster Boot P-value (cyl)",
                 `Model 1` = ".001",
                 `Model 2` = ".002",
                .before = 10) |> 
  dplyr::add_row(term = "Wild Cluster Boot P-value (cyl)",
                 `Model 1` = ".001",
                 `Model 2` = ".005",
                 .before = 22)

bootstrap_table

Now the dataframe is ready to be passed into kableExtra::kbl to further customize it with panel headers/column names etc. Alternatively, you can use the panelsummary::clean_raw function to get a few desirable traits and speed up the process. In particular, the panelsummary::clean_raw function does the following by default:

However, you can also pass in a caption using the caption argument:

## creating a kableExtra object with a few desirable defaults
bootstrap_table |> 
  clean_raw(caption = "A customized panelsummary table with added rows.")

Finally, to get the desired panel labels, you will need to use kableExtra::pack_rows:

## creating the final panels.
bootstrap_table |> 
  clean_raw(caption = "A customized panelsummary table with added rows.") |> 
  kableExtra::pack_rows("Panel A: MPG", 1, 14,
                        italic = T,
                        bold = F) |> 
  kableExtra::pack_rows("Panel B: Cyl", 15, 28, 
                        italic = T,
                        bold = F) |> 
  kableExtra::footnote(list("* p < 0.1, ** p < 0.05, *** p < 0.01")) |> 
  kableExtra::kable_classic(full_width = F, html_font = "Cambria") 


Try the panelsummary package in your browser

Any scripts or data that you put into this service are public.

panelsummary documentation built on Aug. 16, 2023, 9:06 a.m.