【问题标题】:What is the process of applying a dplyr function to a list of values将 dplyr 函数应用于值列表的过程是什么
【发布时间】:2019-09-13 04:14:41
【问题描述】:

我创建了一个 dplyr 函数来评估人口的事件计数。该代码与 dplyr::filter 和 dplyr::group_by 函数中的变量的显式命名一起使用时有效。

我需要将该函数应用于 24 个变量,这些变量是数据框中的列标题。在这里它们被称为 x。

我用过!!据我了解,该变量被评估为字符串而不是列名。

函数

summary_table <- function(x){
  assign(paste(x,"sum_tab", sep="_"),
         envir = parent.frame(),
         value = df %>%
  filter(!is.na(!!x)) %>%
  group_by(!!x) %>%
  summarise(
           'Variable name' = paste0(x),
            Discharged = sum(admission_status == "Discharged"),
           'Re-attended' = sum(!is.na(re_admission_status)),
           'Admitted on Re-attendance' = sum(re_admission_status == "Admitted", na.rm = TRUE)))
}


我用过:

sapply(var_names, summary_table)

但是,这只会为列表 var_names 中的每个变量输出表的一行

总之,我想要指向正确机制的指针,以将上面编写的函数应用于 dplyr 管道中的列名列表。

可重现的示例

example <- mtcars %>%
  group_by(vs) %>%
  summarise(
    '6 cylinder' = sum(cyl == 6),
    'Large disp' = sum(disp >= 100),
    'low gears' = sum(gear <= 4))
})

在本例中,我们希望将此函数应用于以下列表

cars_var <- c("vm", "am", "carb")

这将为列表中的每一列生成三个表格。

【问题讨论】:

  • 您能否提供适用于您的代码的数据示例?这将使您更容易理解您的代码试图做什么并开发解决方案。你打算assign 声明做什么? assign 步骤可能是不必要且不可取的。 !! 是“取消引用”x 参数。但要使其工作,首先必须通过在函数开头执行 x = enquo(x) 来“引用”(或在本例中为“准引用”)x。有关这方面的更多信息,请参阅programming with dplyr
  • 例如我写的here's a recent answer在一个函数中使用了enquo!!
  • 抱歉回复延迟。我在函数中使用了assign,因为我想为函数的每个循环输出一个命名变量。我不确定我是否正确实施了这一点。我看过你的帖子和威克姆的章节。关于我是否应该使用 x = enqote(var_names) 然后使用 !!x 或 enquote(...) 然后使用 !!! 似乎存在矛盾
  • 我添加了一个例子。

标签: r dplyr


【解决方案1】:

正如@eipi10 所评论的,自动创建变量通常是不明智的。一个更好的主意是创建一个作为数据框列表的变量。

让用户使用group_by()group_by_at() 自己应用组也更容易,这样您就不必担心他们如何提供变量的名称。

编辑 2019-05-2

一种方法是将分组变量的名称视为“数据”,并对其进行映射,从而创建按每个分组变量分组的实际数据的副本。

library(dplyr)
library(purrr)

grouping_vars <- c("vs", "am", "carb")
map(grouping_vars, group_by_at, .tbl = mtcars) %>%
  map(summarise,
      '6 cylinder' = sum(cyl == 6),
      'Large disp' = sum(disp >= 100),
      'low gears' = sum(gear <= 4))
#> [[1]]
#> # A tibble: 2 x 4
#>      vs `6 cylinder` `Large disp` `low gears`
#>   <dbl>        <int>        <int>       <int>
#> 1     0            3           18          14
#> 2     1            4            9          13
#> 
#> [[2]]
#> # A tibble: 2 x 4
#>      am `6 cylinder` `Large disp` `low gears`
#>   <dbl>        <int>        <int>       <int>
#> 1     0            4           19          19
#> 2     1            3            8           8
#> 
#> [[3]]
#> # A tibble: 6 x 4
#>    carb `6 cylinder` `Large disp` `low gears`
#>   <dbl>        <int>        <int>       <int>
#> 1     1            2            4           7
#> 2     2            0            8           8
#> 3     3            0            3           3
#> 4     4            4           10           9
#> 5     6            1            1           0
#> 6     8            0            1           0

reprex package (v0.2.1) 于 2019 年 5 月 2 日创建

原答案

这是一个函数,它使用dplyr::groups() 来找出哪些变量已被分组。然后它遍历每个分组变量,汇总并将结果数据框附加到列表中。

library(dplyr)

margins <- function(.data, ...) {
  groups <- dplyr::groups(.data)
  n <- length(groups)
  out <- vector(mode = "list", length = n)
  for (i in rev(seq_len(n))) {
    out[[i]] <-
      .data %>%
      dplyr::group_by(!!groups[[i]]) %>%
      dplyr::summarise(...) %>%
      dplyr::group_by(!!groups[[i]]) # Reapply the original group
  }
  out
}

mtcars %>%
  group_by(vs, am, carb) %>%
  margins('6 cylinder' = sum(cyl == 6),
          'Large disp' = sum(disp >= 100),
          'low gears' = sum(gear <= 4))
#> [[1]]
#> # A tibble: 2 x 4
#> # Groups:   vs [2]
#>      vs `6 cylinder` `Large disp` `low gears`
#>   <dbl>        <int>        <int>       <int>
#> 1     0            3           18          14
#> 2     1            4            9          13
#> 
#> [[2]]
#> # A tibble: 2 x 4
#> # Groups:   am [2]
#>      am `6 cylinder` `Large disp` `low gears`
#>   <dbl>        <int>        <int>       <int>
#> 1     0            4           19          19
#> 2     1            3            8           8
#> 
#> [[3]]
#> # A tibble: 6 x 4
#> # Groups:   carb [6]
#>    carb `6 cylinder` `Large disp` `low gears`
#>   <dbl>        <int>        <int>       <int>
#> 1     1            2            4           7
#> 2     2            0            8           8
#> 3     3            0            3           3
#> 4     4            4           10           9
#> 5     6            1            1           0
#> 6     8            0            1           0

reprex package (v0.2.1.9000) 于 2019 年 4 月 24 日创建

如果要使用变量名向量进行分组,可以使用dplyr::group_by_at()dplyr::vars()

cars_var <- c("vs", "am", "carb")

mtcars %>%
  group_by_at(vars(cars_var)) %>%
  margins('6 cylinder' = sum(cyl == 6),
          'Large disp' = sum(disp >= 100),
          'low gears' = sum(gear <= 4))

我是一个名为 armgin 的小包的作者,它实现了这个和一些类似的想法。

【讨论】:

  • 谢谢,这与我的数据集完美配合,我能够在不重复代码的情况下提取 30 多个汇总表。
  • @hisspot 我添加了一个更简单的答案。
  • 谢谢 我以为会有地图解决方案版本。太好了。
猜你喜欢
  • 1970-01-01
  • 2015-08-25
  • 1970-01-01
  • 1970-01-01
  • 2017-08-10
  • 2015-02-23
  • 2020-03-05
  • 2014-03-16
相关资源
最近更新 更多