Tidyeval:将函数应用于从列表中提取的数据框

Tidyeval: apply function to data frames extracted from list

这是涉及包含复杂 table 的大型列表的问题的简化版本。我想从列表中提取 tables 并为每个应用一个函数。在这里,我们可以创建一个包含小型命名数据框的简单列表:

library(tidyverse)

table_names <- c('dfA', 'dfB', 'dfC')

dfA <- tibble(a = 1:3, b = 4:6, c = 7:9)
dfB <- tibble(a = 10:12, b = 13:15, c = 16:18)
dfC <- tibble(a = 19:21, b = 22:24, c = 25:27)

df_list <- list(dfA, dfB, dfC) %>% setNames(table_names)

这是我想要应用的操作类型的简化示例:

dfA_mod <- df_list$dfA %>% 
  mutate(name = 'dfA') %>%
  select(name, everything()) 

在此示例中,我提取列表 df_list$dfA 中的三个 table 之一,在每一行中创建一个具有相同值的新列 mutate(name = 'dfA'),然后重新排序列,以便新列出现在最左侧的位置 select(name, everything())。生成的对象分配给 dfA_mod.

为了解决更大的问题,我想使用 purrr::map() 变体之一将函数应用于字符向量 table_names,这是在上面的第一段代码中启动的。 table_names 的元素有两个用途:1) 命名列表中的 table;和 2) 为修改后的 table.

中的 name 列提供值

我可以编写如下函数:

fun <- function(x) {
df_list$x %>% 
  mutate(name = x) %>%
  select(name, everything()) %>%
  assign(paste0(x, '_mod'), ., envir = .GlobalEnv)
}

然后使用map()创建一个新的修改列表tables:

new_list <- df_list %>% map(table_name, fun(x))

但是当然这段代码不起作用,主要障碍是(至少对我而言)弄清楚如何在函数中引用和取消引用正确的术语。我是整洁评估的初学者,我可以在指定函数和正确使用 map 方面使用一些帮助。

这是所需的输出(修改后的 table):

# A tibble: 3 x 4
  name      a     b     c
  <chr> <int> <int> <int>
1 dfA       1     4     7
2 dfA       2     5     8
3 dfA       3     6     9

在此先感谢您的帮助!

我们可以使用 purrr::imap 传递列表中的数据以及列表的名称

library(dplyr)
library(purrr)

df_out <- imap(df_list, ~.x %>% mutate(name = .y) %>% select(name, everything()))
df_out

#$dfA
# A tibble: 3 x 4
#  name      a     b     c
#  <chr> <int> <int> <int>
#1 dfA       1     4     7
#2 dfA       2     5     8
#3 dfA       3     6     9

#$dfB
# A tibble: 3 x 4
#  name      a     b     c
#  <chr> <int> <int> <int>
#1 dfB      10    13    16
#....
#....

这给出了所需数据帧的列表,如果您希望它们作为单独的数据帧,您可以这样做

names(df_out) <- paste0(names(df_out), "_mod")
list2env(df_out, .GlobalEnv)

我们也可以使用 base R Map

df_out <- Map(function(x, y) transform(x, name = y)[c('name', names(x))], 
                               df_list, names(df_list))

并给出与上面相同的列表名称。

我们可以将其转换为带有 map 的单个 data.frame,同时传递 .id

library(purrr)
map_dfr(df_list,  I, .id = 'name')

bind_rows

library(dplyr)
bind_rows(df_list, .id = 'name')
# A tibble: 9 x 4
#  name      a     b     c
#  <chr> <int> <int> <int>
#1 dfA       1     4     7
#2 dfA       2     5     8
#3 dfA       3     6     9
#4 dfB      10    13    16
#5 dfB      11    14    17
#6 dfB      12    15    18
#7 dfC      19    22    25
#8 dfC      20    23    26
#9 dfC      21    24    27