Return 从循环到新数据帧的数据帧的名称作为 ID

Return the names of data frames from a loop into a new data frame as IDs

假设我有多个具有相同前缀和相同结构的数据帧。

mydf_1 <- data.frame('fruit' = 'apples', 'n' = 2)
mydf_2 <- data.frame('fruit' = 'pears', 'n' = 0)
mydf_3 <- data.frame('fruit' = 'oranges', 'n' = 3)

我有一个 for 循环,它获取所有带有此前缀的 table,并附加那些匹配特定条件的。

res <- data.frame()

for(i in mget(apropos("^mydf_"), envir = .GlobalEnv)){
  
  if(sum(i$n) > 0){
    res <- rbind.data.frame(res, data.frame('name' = paste0(i[1]),
                                            'n' = sum(i$n)))
  }
}

res

这很好用,但我希望我的 'res' table 在 'name' 列中识别原始数据框本身的名称,而不是列名称。 我想要的结果是:

我最接近解决这个问题的是:

'name' = paste0(substitute(i))

而不是

'name' = paste0(i[1])

但它只是 returns 'i'.

有什么简单的解决办法吗?首选基础但不是必需的。

要绑定 data.frames 的列表并将列表名称存储为新列,一种方便的方法是在 dplyr::bind_rows().

中设置参数 .id
library(dplyr)

mget(apropos("^mydf_")) %>%
  bind_rows(.id = "name") %>%
  count(name, wt = n) %>%
  filter(n > 0)

#     name n
# 1 mydf_1 2
# 2 mydf_3 3

如评论中所述,最好将数据帧放入列表中,因为这样更容易处理和操作它们。但是,我们仍然可以从全局环境中获取数据帧,获取每个数据帧的总和,然后将它们绑定在一起并将数据帧名称添加为一行。

library(tidyverse)

df_list <-
  do.call("list", mget(grep("^mydf_", names(.GlobalEnv), value = TRUE))) %>%
  map(., ~ .x %>% summarise(n = sum(n))) %>%
  discard(~ .x == 0) %>% 
  bind_rows(., .id = "name")

或者我们可以使用map_dfr绑定在一起并汇总,然后过滤掉0值:

map_dfr(mget(ls(pattern = "^mydf_")), ~ c(n = sum(.x$n)), .id = "name") %>%
  filter(n != 0)

输出

    name n
1 mydf_1 2
2 mydf_3 3