使用tidyverse创建汇总表

时间:2018-03-06 02:41:21

标签: r tidyverse

Q1。是否有更直接(但仍然tidyverse)方式来创建这样的摘要表?

enter image description here

library(tidyverse)
library(knitr)
library(kableExtra)
df <- data.frame(group=c(1, 1, 1, 1, 0, 0, 0, 0),
                 v1=c(1, 2, 3, 4, 5, 6, 1, 2),
                 v2=c(4, 3, 2, 5, 3, 5, 3, 8),
                 v3=c(0, 1, 0, 1, 1, 0, 1, 1))

df %>%
  group_by(group) %>%
  summarise(v1=paste0(round(mean(v1), 2),
                      " (",
                      round(sd(v1), 2),
                      ")"),
            v2=paste0(round(mean(v2), 2),
                      " (",
                      round(sd(v2), 2),
                      ")"),
            v3=round(mean(v3)*100, 1)
  ) %>%
  dplyr::select(-group) %>%
  t() %>%
  `rownames<-` (c("v1 mean (SD)",
                  "v2 mean (SD)",
                   "Percent v3")) %>%
  kable("html",
        col.names=c("Group 0", "Group 1")) %>%
  kable_styling()

Q2。与此相关,有没有办法在不重复summarise代码的情况下合并两个summarise级别(例如,没有分组+分组)?

enter image description here

all <- 
df %>%
  summarise(v1=paste0(round(mean(v1), 2),
                      " (",
                      round(sd(v1), 2),
                      ")"),
            v2=paste0(round(mean(v2), 2),
                      " (",
                      round(sd(v2), 2),
                      ")"),
            v3=round(mean(v3)*100, 1)
  ) %>%
  t() %>%
  `rownames<-` (c("v1 mean (SD)",
                  "v2 mean (SD)",
                   "Percent v3")) 

groups <- 
  df %>%
  group_by(group) %>%
  summarise(v1=paste0(round(mean(v1), 2),
                      " (",
                      round(sd(v1), 2),
                      ")"),
            v2=paste0(round(mean(v2), 2),
                      " (",
                      round(sd(v2), 2),
                      ")"),
            v3=round(mean(v3)*100, 1)
  ) %>%
  dplyr::select(-group) %>%
  t() %>%
  `rownames<-` (c("v1 mean (SD)",
                  "v2 mean (SD)",
                  "Percent v3")) 

all %>%
  cbind(groups) %>%
  kable("html",
        col.names=c("All", "Group 0", "Group 1")) %>%
  kable_styling()

2 个答案:

答案 0 :(得分:1)

一个解决方案(特别是如果你想在将来扩展列数v1,v2,...)以使你的代码更简洁可能是,paste0(round(mean(v1), 2)," (", round(sd(v1), 2), ")")放入一个函数:{ {1}}。

这会缩短您的“管道”并使其更易于阅读:

paste_mean_and_sd = function(df_col){paste0(round(mean(df_col), 2)," (", round(sd(df_col), 2), ")")}

答案 1 :(得分:1)

这是我能想到的最低限度。

cat_var <- "v3"

df_cal <- function(x, var) {
  if (var[1] %in% cat_var) return(as.character(round(mean(x), 1)))
  paste0(mean(x), " (", round(sd(x), 2), ")")
}

df_tall <- df %>% gather(var, x, v1:v3) %>% group_by(var)

all <- df_tall %>% summarise(stat = df_cal(x, var)) %>% mutate(group = -1)
groups <- df_tall %>% group_by(group, var) %>% summarise(stat = df_cal(x, var)) 

bind_rows(all, groups) %>%
  ungroup() %>%
  mutate(var = factor(var, labels = c(
    "v1 mean (SD)", "v2 mean (SD)", "Precent v3"
  ))) %>%
  spread(group, stat) %>%
  kable("html", col.names = c(" ", "All", "Group 0", "Group 1")) %>%
  kable_styling()