mda08rds
mda08rds

Reputation: 71

Group rows by a variable in R (knitr::kable)

I'm trying to group the rows of the kable output by the value in the Person column, so the table output is easier to read.

Data for MRE (within an R markdown document, using R Studio 2022.07.1 on Mac OS Ventura 13.2)

library ("tidyverse")
library ("knitr")

Person <- c("A", "A", "B", "B", "C", "C")
Group <- c("pre", "post", "pre", "post", "pre", "post")
Value <- c("10", "5", "8", "4", "5", "4")

df <- tibble(Login,Group,Value)

knitr::kable(df, format = "pipe")

In this output, each row displays its Person value.

I've seen how you can use pack_rows() or group_rows() to manually define groups, but I would like this to be grouped by Person value, rather than be having to define each Person and their relevant two rows.

The current output looks like thisenter image description here

My desired output looks more like this

enter image description here

Upvotes: 4

Views: 2233

Answers (4)

the_kipper
the_kipper

Reputation: 89

I am late on this but I was dealing with a similar issue that I found a solution for. This is for anyone else who might need this as well.

library("kableExtra")

Person <- c("A", "A", "B", "B", "C", "C")
Group <- c("pre", "post", "pre", "post", "pre", "post")
Value <- c("10", "5", "8", "4", "5", "4")

df <- tibble(Person,Group,Value)

df[,c("Group","Value")] %>% 
  kbl(table.attr = "style='width:25%;'", caption = "Caption",align = "c") %>%  
  kable_styling(bootstrap_options = "striped", font_size = 12, position = "center") %>% 
  pack_rows(index=rowSums(table(df$Person,df$Group)))

enter image description here

Upvotes: 1

Brian Brummer
Brian Brummer

Reputation: 98

You could also use xtabs:

*change "Value" to numeric first

df$Value <- as.numeric(df$Value)
xtabs(Value ~ Group + Person)

and if you want to present it in all various formats, something along the lines of :

Library(gtsummary)
tbl_strata <- df %>%tbl_strata(
strata = Person,
.tbl_fun =
  ~ .x %>%
  tbl_summary(by = Group,
              type = list(Value ~ "continuous"),
              statistic = all_continuous() ~ "{sum}")
)
tbl_strata
  • note that you have to specify that continuous variables should be presented as such when using small datasets

is this format maybe a bit closer to what you had in mind?

edit:

you can also use a huxtable. They are also nicely compatible with Rmakrdown

okay, have a look at huxtables. they have the added benefit of also beign nicely compatible with Rmarkdown.

df <- df %>% hux() %>%
   merge_repeated_rows()%>%
   set_bottom_border(, row = odds, col = everywhere)
df

Upvotes: 1

Peter
Peter

Reputation: 12699

Using kableExtra::collapse_rows()...

This approach assumes you are printing to pdf. There are multiple options within kableExtra to finetune the appearance of the table.

---
output: pdf_document
---

```{r}

library(tibble)
library (kableExtra)

Person <- c("A", "A", "B", "B", "C", "C")
Group <- c("pre", "post", "pre", "post", "pre", "post")
Value <- c("10", "5", "8", "4", "5", "4")

df <- tibble(Person, Group, Value)

  kbl(df, booktabs = TRUE) |> 
  collapse_rows(valign = "top",
                latex_hline = "major")

```

enter image description here

Upvotes: 2

Quinten
Quinten

Reputation: 41285

You could also transform your data to a wider format using pivot_wider like this:

Person <- c("A", "A", "B", "B", "C", "C")
Group <- c("pre", "post", "pre", "post", "pre", "post")
Value <- c("10", "5", "8", "4", "5", "4")

library(tibble)
library(tidyr)
df <- tibble(Person,Group,Value)
df <- pivot_wider(df, names_from = Group, values_from = Value)
knitr::kable(df, format = "pipe")
Person pre post
A 10 5
B 8 4
C 5 4

Created on 2023-02-06 with reprex v2.0.2

Upvotes: 2

Related Questions