Dplyr函数计算平均值、n、标准差和标准误差。

5

我发现自己经常编写这段代码来生成组均值的标准误差(然后用于绘制置信区间)。

不过,能够写出自己的函数一行代码完成这个任务会很好。我已经阅读了dplyr中关于非标准评估的nse文献和这篇博客文章。虽然我有点明白,但我还是太菜了,无法自己解决问题。有人可以帮忙吗?谢谢。

var1<-sample(c('red', 'green'), size=10, replace=T)
var2<-rnorm(10, mean=5, sd=1)
df<-data.frame(var1, var2)
df %>% 
group_by(var1) %>% 
summarize(avg=mean(var2), n=n(), sd=sd(var2), se=sd/sqrt(n))

你能展示一下你尝试过什么吗?你卡在哪里了?看看[nse]标签下的一些问题。 - Axeman
好的,我在博客文章中尝试了以下代码:codemean_mpg = function(data, ..., x) { data %>% group_by_(.dots = lazyeval::lazy_dots(...)) %>% summarize(mean_mpg = ~mean(x)) }mtcars %>% mean_mpg(cyl, gear, mpg) code 它返回了错误信息“不是向量”。 - spindoctor
1个回答

9
您可以使用函数enquo在函数调用中明确命名变量:
my_fun <- function(x, cat_var, num_var){
  cat_var <- enquo(cat_var)
  num_var <- enquo(num_var)

  x %>%
    group_by(!!cat_var) %>%
    summarize(avg = mean(!!num_var), n = n(), 
              sd = sd(!!num_var), se = sd/sqrt(n))
}

这将为您提供:

> my_fun(df, var1, var2)
# A tibble: 2 x 5
    var1      avg     n        sd        se
  <fctr>    <dbl> <int>     <dbl>     <dbl>
1  green 4.873617     7 0.7515280 0.2840509
2    red 5.337151     3 0.1383129 0.0798550

并且与您的示例输出匹配:
> df %>% 
+   group_by(var1) %>% 
+   summarize(avg=mean(var2), n=n(), sd=sd(var2), se=sd/sqrt(n))
# A tibble: 2 x 5
    var1      avg     n        sd        se
  <fctr>    <dbl> <int>     <dbl>     <dbl>
1  green 4.873617     7 0.7515280 0.2840509
2    red 5.337151     3 0.1383129 0.0798550

编辑:

楼主要求从函数中删除group_by语句,以添加按多个变量分组的功能。在我看来,有两种方法可以解决这个问题。首先,您可以简单地删除group_by语句,并将分组数据帧管道传递到函数中。该方法如下:

my_fun <- function(x, num_var){
  num_var <- enquo(num_var)

  x %>%
    summarize(avg = mean(!!num_var), n = n(), 
              sd = sd(!!num_var), se = sd/sqrt(n))
}

df %>%
  group_by(var1) %>%
  my_fun(var2)

另一种实现方法是使用...quos,以便函数能够捕获多个group_by语句的参数。代码如下:

#first, build the new dataframe
var1<-sample(c('red', 'green'), size=10, replace=T)
var2<-rnorm(10, mean=5, sd=1)
var3 <- sample(c("A", "B"), size = 10, replace = TRUE)
df<-data.frame(var1, var2, var3)

# using the first version `my_fun`, it would look like this
df %>%
  group_by(var1, var3) %>%
  my_fun(var2)

# A tibble: 4 x 6
# Groups:   var1 [?]
    var1   var3      avg     n        sd        se
  <fctr> <fctr>    <dbl> <int>     <dbl>     <dbl>
1  green      A 5.248095     1       NaN       NaN
2  green      B 5.589881     2 0.7252621 0.5128378
3    red      A 5.364265     2 0.5748759 0.4064986
4    red      B 4.908226     5 1.1437186 0.5114865

# Now doing it with a new function `my_fun2`
my_fun2 <- function(x, num_var, ...){
  group_var <- quos(...)
  num_var <- enquo(num_var)

  x %>%
    group_by(!!!group_var) %>%
    summarize(avg = mean(!!num_var), n = n(), 
              sd = sd(!!num_var), se = sd/sqrt(n))
}

df %>%
  my_fun2(var2, var1, var3)

# A tibble: 4 x 6
# Groups:   var1 [?]
    var1   var3      avg     n        sd        se
  <fctr> <fctr>    <dbl> <int>     <dbl>     <dbl>
1  green      A 5.248095     1       NaN       NaN
2  green      B 5.589881     2 0.7252621 0.5128378
3    red      A 5.364265     2 0.5748759 0.4064986
4    red      B 4.908226     5 1.1437186 0.5114865

你可能需要注意这个只能在 dplyr 的开发版本中运行,而 不是 当前的 CRAN 版本,而 OP 很可能正在使用该版本。 - Axeman
我终于回来了,我忘记了我曾经问过这个问题。但是在函数中是否可能包括分类分组变量?有时我按一个变量分组,有时按两个变量分组。我想在自定义函数之外保持这种灵活性。但我不知道是否可能。 - spindoctor
我已经添加了一个编辑功能,让你可以以两种不同的方式完成这个操作。 - tbradley
这很棒,我一直在使用它,但我觉得像这样的函数应该在某个包中。有人知道这是否在 tidyverse 友好的包中吗? - spindoctor

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