映射列并应用自定义函数

use*_*230 4 r dplyr purrr

这里遗漏了一些小东西,并且努力将列传递到函数中。我只想map(或lapply)遍历列并在每个列上执行自定义函数。这里是最小的例子:

library(tidyverse)
set.seed(10)
df <- data.frame(id = c(1,1,1,2,3,3,3,3),
                    r_r1 = sample(c(0,1), 8, replace =  T),
                    r_r2 = sample(c(0,1), 8, replace =  T),
                    r_r3 = sample(c(0,1), 8, replace =  T))
df
#   id r_r1 r_r2 r_r3
# 1  1    0    0    1
# 2  1    0    0    1
# 3  1    1    0    1
# 4  2    1    1    0
# 5  3    1    0    0
# 6  3    0    0    1
# 7  3    1    1    1
# 8  3    1    0    0
Run Code Online (Sandbox Code Playgroud)

一个仅用于过滤和计算数据集中剩余的唯一 ID 的函数:

cnt_un <-  function(var) {
  df %>% 
    filter({{var}} == 1) %>% 
    group_by({{var}}) %>% 
    summarise(n_uniq = n_distinct(id)) %>% 
    ungroup()
}
Run Code Online (Sandbox Code Playgroud)

它在地图之外工作

cnt_un(r_r1)
# A tibble: 1 x 2
   r_r1 n_uniq
  <dbl>  <int>
1     1      3
Run Code Online (Sandbox Code Playgroud)

我想将该函数应用于所有r_r列以获得类似以下内容:

df2
#      y n_uniq
# 1 r_r1      3
# 2 r_r2      2
# 3 r_r3      2
Run Code Online (Sandbox Code Playgroud)

我认为以下内容会起作用,但没有

map(dplyr::select(df, matches("r_r")), ~ cnt_un(.x))
Run Code Online (Sandbox Code Playgroud)

有什么建议么?谢谢

cam*_*lle 6

我不确定是否有直接的整洁方法可以用类似的东西来做到这一点map。您遇到的问题是,在调用 时,函数在 的每一列上作为向量map(df, *whatever_function*)被调用,而您的函数需要 tidyeval 样式的裸列名称。df为了验证:

map(df, class)
Run Code Online (Sandbox Code Playgroud)

"numeric"将为每一列返回。

另一种方法是将列名作为字符串进行迭代,并将其转换为符号;这仅需要函数中增加一行。

map(df, class)
Run Code Online (Sandbox Code Playgroud)

调用该函数有点尴尬,因为它只保留相关的列名称(调用"r_r1"gets columns"r_r1""n_uniq"等)。一种方法是获取所需的列名称向量,对其进行命名,以便您可以在 中添加 ID 列map_dfr,然后删除多余的列,因为它们大部分是NA

library(dplyr)
library(tidyr)
library(purrr)

cnt_un_name <- function(varname) {
  var <- ensym(varname)
  df %>% 
    filter({{var}} == 1) %>% 
    group_by({{var}}) %>% 
    summarise(n_uniq = n_distinct(id)) %>% 
    ungroup()
}
Run Code Online (Sandbox Code Playgroud)

更好的方法是调用该函数,然后在整形后进行绑定。

grep("^r_r\\d+", names(df), value = TRUE) %>%
  set_names() %>%
  map_dfr(cnt_un_name, .id = "y") %>%
  select(y, n_uniq)
#> # A tibble: 3 x 2
#>   y     n_uniq
#>   <chr>  <int>
#> 1 r_r1       3
#> 2 r_r2       2
#> 3 r_r3       2
Run Code Online (Sandbox Code Playgroud)

或者(也许更好/更具可扩展性)是在函数定义内进行列重命名。