dplyr使用summarise_all函数与quantile和其他函数

4

我有一个名为 "PatientA" 的数据框。

    Height Weight   Age   BMI
    <dbl>  <dbl> <dbl> <dbl>
 1   161    72.2    27  27.9
 2   164    61.0    21  22.8
 3   171    72.0    30  24.6
 4   169.   63.9    25  22.9
 5   174.   64.4    27  21.1
 6   160    50.9    22  19.9
 7   172    77.5    22  26.3
 8   165    54.5    22  20  
 9   173    82.4    29  27.5
10   169    76.6    22  26.9

我希望你能为每列提供一些统计数据。我有下面这段有效的代码,只处理分位数。

genStat <- PatientsA  %>%
  summarise_all(funs(list(quantile(., probs = c(0.25, 0.5, 0.75))))) %>%
  unnest %>%
  transpose %>%
  setNames(., c('25%', '50%', '75%')) %>%
  map_df(unlist) %>%
  bind_cols(data.frame(vars = names(PatientsA)), .)

我需要在summarise_all中添加平均值和标准差,像这样:

genStat <- PatientsA  %>%
      summarise_all(funs(mean,sd,list(quantile(., probs = c(0.25, 0.5, 0.75))))) %>%
      unnest %>%
      transpose %>%
      setNames(., c('mean','sd','25%', '50%', '75%')) %>%
      map_df(unlist) %>%
      bind_cols(data.frame(vars = names(PatientsA)), .)

这种直接的方法失败了,返回了下列错误:

Error in names(object) <- nm : 'names'属性[5]必须与向量[3]的长度相同

我是R的新手,那么完成此任务的正确语法是什么?


你可能想要查看skimr包。 - Elin
2
如果在尝试设置名称之前查看数据,它是否具有您期望的确切列数?尝试在“转置”后立即停止并查看数据的外观。 - r2evans
好的,我明白发生了什么。但是不知道如何快速修复它。 - Artem Zefirov
你可以尝试使用 purrr::invoke_map 来一次性调用一个函数列表和参数列表。 - camille
3个回答

3
这是我的建议。代码中有一些重复(调用quantile三次),但总体来说,我认为它更易于理解和调试。
library(tidyverse)    

PatientsA %>% 
  gather("variable", "value") %>% 
  group_by(variable) %>% 
  summarize(mean_val = mean(value), 
            sd_val = sd(value), 
            q25 = quantile(value, probs = .25),
            q50 = quantile(value, probs = .5),
            q75 = quantile(value, probs = .75))


## A tibble: 4 x 6
#  variable mean_val sd_val   q25   q50   q75
#  <chr>       <dbl>  <dbl> <dbl> <dbl> <dbl>
#1 Age          24.7   3.33  22    23.5  27  
#2 BMI          24.0   3.08  21.5  23.8  26.7
#3 Height      168.    5.01 164.  169   172. 
#4 Weight       67.5  10.3   61.7  68.2  75.5

2
这基本上就是 skimr 中我们所做的事情。 - Elin

3
我们也可以把quantile的输出放到一个list中,然后使用unnest进行展开。
library(tidyverse)
PatientsA %>% 
   gather %>% 
   group_by(key) %>%
   summarise_at(vars('value'), 
    funs(mean, 
         sd, 
         quantile = list(as.tibble(as.list(quantile(., 
                   probs = c(0.25, 0.5, 0.75))))))) %>%
   unnest
# A tibble: 4 x 6
#  key     mean    sd `25%` `50%` `75%`
#   <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>
#1 Age     24.7  3.33  22    23.5  27  
#2 BMI     24.0  3.08  21.5  23.8  26.7
#3 Height 168.   5.01 164.  169   172. 
#4 Weight  67.5 10.3   61.7  68.2  75.5

或者使用 pivot_longer

PatientsA %>%
    pivot_longer(cols = everything()) %>% 
    group_by(name) %>%
    summarise(across(value, list(mean= ~ mean(., na.rm = TRUE), 
         sd = ~ sd(., na.rm = TRUE), 
         quantile = ~ list(as_tibble(as.list(quantile(., 
                   probs = c(0.25, 0.5, 0.75)))))))) %>% 
   unnest(c(value_quantile))
# A tibble: 4 x 6
  name   value_mean value_sd `25%` `50%` `75%`
  <chr>       <dbl>    <dbl> <dbl> <dbl> <dbl>
1 Age          24.7     3.33  22    23.5  27  
2 BMI          24.0     3.08  21.5  23.8  26.7
3 Height      168.      5.01 164.  169   172. 
4 Weight       67.5    10.3   61.7  68.2  75.5

###数据

PatientsA <- structure(list(Height = c(161, 164, 171, 169, 174, 160, 172, 
 165, 173, 169), Weight = c(72.2, 61, 72, 63.9, 64.4, 50.9, 77.5, 
 54.5, 82.4, 76.6), Age = c(27L, 21L, 30L, 25L, 27L, 22L, 22L, 
 22L, 29L, 22L), BMI = c(27.9, 22.8, 24.6, 22.9, 21.1, 19.9, 26.3, 
 20, 27.5, 26.9)), class = "data.frame", row.names = c("1", "2", 
 "3", "4", "5", "6", "7", "8", "9", "10"))

1
弃用的元素。可能需要更新此内容。 - EngrStudent

0
dplyr 1.1.0 开始,我们可以使用更加程序化的解决方案,结合 reframe()pivot_[longer|wider]group_by 来实现。
library(dplyr)
library(tidyr)

stat_df <- function(x, probs = c(0.25, 0.5, 0.75)){
  tibble(
    val = c(
      mean(x, na.rm = TRUE),
      sd(x, na.rm = TRUE),
      quantile(x, probs, na.rm = TRUE)
    ),
    stat = c("mean", "sd", paste(probs * 100, "%"))
  )
}

PatientsA %>%
  pivot_longer(everything()) %>%
  group_by(name) %>%
  reframe(quantile_df(value)) %>%
  pivot_wider(names_from = stat, values_from = val)

# # A tibble: 4 × 6
#   name    mean    sd `25 %` `50 %` `75 %`
#   <chr>  <dbl> <dbl>  <dbl>  <dbl>  <dbl>
#   1 Age     24.7  3.33   22     23.5   27  
# 2 BMI     24.0  3.08   21.5   23.8   26.7
# 3 Height 168.   5.01  164.   169    172. 
# 4 Weight  67.5 10.3    61.7   68.2   75.5

它帮助我动态添加了probs = 0:100/100,这比写出所有内容要容易得多。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接