使用.id使带有purrr :: map_df的输入项列不复制命名向量的输入

时间:2018-11-15 02:24:56

标签: r purrr

我经常想映射数据框中列名称的向量,并使用.id参数跟踪输出。但是,要将与每个map迭代相关的列名称写入该.id列,似乎需要在输入向量中将它们的名称加倍-换句话说,通过用自己的名称命名每个列名称。如果我没有使用自己的名称来命名列,那么.id仅存储迭代的索引。

根据purrr::map docs,这是预期的行为:

  

.id
  字符串或NULL。如果是字符串,则输出将包含具有该名称的变量,该变量存储输入的名称(如果已命名.x)或索引(如果未命名.x)。

但是我的方法有点笨拙,所以我想我缺少了一些东西。有没有更好的方法来获取要迭代的列的列表,而又不需要在输入向量中每次写两次列名?任何建议将不胜感激!

下面是一个可以使用的示例:

library(rlang)
library(tidyverse)

tb <- tibble(foo = rnorm(10), bar = rnorm(10))

cols_once <- c("foo", "bar")
cols_once %>% map_dfr(~ tb %>% summarise(avg = mean(!!sym(.x))), .id="var")
# A tibble: 2 x 2
  var       avg   <-- var stores only the iteration index
  <chr>   <dbl>
1 1     -0.0519
2 2      0.204 

cols_twice <- c("foo" = "foo", "bar" = "bar")
cols_twice %>% map_dfr(~ tb %>% summarise(avg = mean(!!sym(.x))), .id="var")
# A tibble: 2 x 2
  var       avg   <-- var stores the column names
  <chr>   <dbl>
1 foo   -0.0519
2 bar    0.204 

2 个答案:

答案 0 :(得分:3)

这是使用summarize_atgather针对您的特定情况的替代解决方案:

tb %>% summarize_at( cols_once, mean ) %>% gather( var, avg )
# # A tibble: 2 x 2
#   var      avg
#   <chr>  <dbl>
# 1 foo   0.374 
# 2 bar   0.0397

在更一般的情况下,由于您在问题中指出了预期的行为,因此我认为在使用cols_once时没有办法命名map_dfr。但是,您可以将{snake case“包装器用于setNames(),以使其更加美观:

cols_once %>% set_names %>% 
  map_dfr(~ tb %>% summarise(avg = mean(!!sym(.x))), .id="var")
# # A tibble: 2 x 2
#   var      avg
#   <chr>  <dbl>
# 1 foo   0.374 
# 2 bar   0.0397

答案 1 :(得分:1)

您可以使用以下方法轻松创建输入向量:

setNames(names(tb), names(tb))

因此您的代码应为:

setNames(names(tb), names(tb)) %>%
  map_dfr(~ tb %>% summarise(avg = mean(!!sym(.x))), .id="var")

根据您的评论进行编辑:

仍然不是您想要的解决方案,但是当您不使用所有列名时,仍然可以使用setNames()并将所需的子集进行子集化(或将不需要的子集化出)

tb <- tibble(foo = rnorm(10), bar = rnorm(10), taz = rnorm(10))

setNames(names(tb), names(tb))[-3]