这里遗漏了一些小东西,并且努力将列传递到函数中。我只想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)
有什么建议么?谢谢
我不确定是否有直接的整洁方法可以用类似的东西来做到这一点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)
或者(也许更好/更具可扩展性)是在函数定义内进行列重命名。