r - 使用列名执行 `map` 时如何使用准引用/整洁评估

标签 r tidyverse purrr tidy

您能帮我了解准报价的工作原理吗? 我正在使用 map 和计数功能,但它似乎无法正常工作。

第一次尝试:

map(names(starwars),~starwars %>% count(.x))
Error: Column `.x` is unknown

第二次尝试:

map(names(starwars),~starwars %>% count(!!.x))
#not useful [[1]]
# A tibble: 1 x 2
  `"name"`     n
  <chr>    <int>
1 name        87

[[2]]
# A tibble: 1 x 2
  `"height"`     n
  <chr>      <int>
1 height        87

第三次尝试:

map(names(starwars),~starwars %>% count(!!!.x))
# the same

另一个例子(处理函数):

如果我想创建一个接受列表和 相对于前一个元素更改列表中的每个元素 在该列表中:

my_list <- list("a" =1 , "b" = 2, "c" = 3)

# this obviously is not working (list + number)
> my_list+1
Error in my_list + 1 : non-numeric argument to binary operator
# this is a bit strange
my_list %>% map(~+1)
#this works fine
my_list %>% map(+1)
# as this
my_list %>% map(~.x+1)

# moving on to add the previous element to the next element
imap(my_list, my_list[[.y +1]] := .x %>% +1)
Error in `:=`(my_list[[.y + 1]], .x %>% +1) : could not find function ":="

# wrong eval 1?
imap(my_list, my_list[[.y +1]] <- .x %>% +1)
Error in eval(lhs, parent, parent) : object '.x' not found

# wrong eval 2?
imap(my_list, my_list[[.y +1]] <- !!.x %>% +1)
Error in eval(lhs, parent, parent) : object '.x' not found

# wrong symbol 1?
imap(my_list, my_list[[.y +1]] = .x %>% +1)
Error: unexpected '=' in "imap(my_list, my_list[[.y +1]] ="

最佳答案

我认为这个问题可以分解为准引用部分和 map 函数部分。

首先,~ starwars %>% count(.x))function(.x){starwars %>% count(.x) 的简写形式,也是稍微复杂一点的版本)}。所以我将直接使用这些函数。

其次,names(starwars) 为您提供一个字符向量。

因此,为了避免 map 带来的困惑,让我们从函数开始,并向它们传递字符“eye_color”。

尝试 1:dplyr 函数将符号视为表中的列

dplyr 函数在进行交互式数据分析时非常有用,因为它们允许我们使用符号引用列。我建议阅读: https://dplyr.tidyverse.org/articles/programming.html了解更多信息。

func <- function(.x) { starwars %>% count(.x) }
func("eye_color")
Error: Column `.x` is unknown

在你的第一次尝试中,这会导致一个问题,因为 .x 是符号,所以 R 认为 .xstarwars 中的列.

尝试 2/3:count()/group_by() 期望符号而不是字符输入。

!! 采用 .x 并将其替换为“eye_color”。但“eye_color”不是符号/名称,而是一个字符。

func_2 <- function(.x) { starwars %>% count(!!.x) }
func_2("eye_color")

# A tibble: 1 x 2
  `"eye_color"`     n
  <chr>         <int>
1 eye_color        87

这个奇怪的输出是按字符分组的结果。无论出于何种原因,dplyr 将整个数据帧分组为“eye_color”,然后告诉您有 87 行。 starwars %>% count("hooray") 给出类似的输出。

插曲:我们想要的是一个符号

编码 dplyr 函数的一种直观方法是传递符号/名称并使用 {{.x}} 来评估 promise 。 (不太直观,您可以执行 !!enquo(.x)。)

func_3 <- function(.x) {  starwars %>% count({{.x}}) }
func_3(eye_color)

# A tibble: 15 x 2
   eye_color         n
   <chr>         <int>
 1 black            10
 2 blue             19
 3 ...

这有效!

解决方案是将字符转换为符号

func_4 <- function(.x) { .x = as.symbol(.x)
                         starwars %>% count({{.x}}) }
func_4("eye_color")

# A tibble: 15 x 2
   eye_color         n
   <chr>         <int>
 1 black            10
 2 blue             19
 3 ...

这也有效!

带回 map

在继续之前,我认为 nniloc 的解决方案更适合您的问题。

但是你可以按如下方式使用 map

starwars %>% 
  select_if(negate(is.list)) %>% 
  names() %>% 
  map(function(.x) {x = as.symbol(.x)
      starwars %>% count( {{ x }} )
      }) 

starwars %>% 
  select_if(negate(is.list)) %>% 
  names() %>% 
  map(as.symbol) %>%
  map(function(.x) { 
      starwars %>% count( {{  .x }} )
      }) 

当您使用~表示法时,.x现在是直接引用符号的“代词”,因此我们可以使用!! 直接访问符号。 (我不太明白这一点)。

starwars %>% 
  select_if(negate(is.list)) %>% 
  names() %>% 
  map(as.symbol) %>%
  map(~ starwars %>% count( !! .x  )) 

关于imap(),看起来您想用Python(或其他带有迭代的语言)进行编码。 imap()map2(.x, names(.x), ...) 的简写,因此与 enumerate() 不同在Python中。有像 seq_along 这样的 R 函数可以给你在对象中的位置,但我还没有将它们与 map 一起使用。

关于r - 使用列名执行 `map` 时如何使用准引用/整洁评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61139475/

相关文章:

r - 如何删除一行,字符串以空格开头?

R - 将列值嵌套到单个向量列(类型列表)中

r - 如何找到 Id 并将其放入新列

r - 根据存储在 data.frame 中的单独字符向量,有条件地重命名列表中的列

r - 使用 purrr 根据嵌套数据框列中的数据进行过滤

java - java中的广义线性混合效应模型

r - 检查变量是否是 R 中特定函数的结果

r - 使用dplyr填写缺失值(通过联接吗?)

r - 在 purrr::map() 中使用 dplyr::count() 时出错

r - 如何保持数据框中每个ID的第一次出现