在使用列名进行“映射”时如何使用准引用/整洁评估
How to use quasiquotation / tidy evaluation when doing `map` with column names
你能帮我理解准报价的工作原理吗?
我正在使用地图和计数功能,但它似乎无法正常工作。
第一次尝试:
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]] ="
我认为这个问题可以分解为 quasi-quotation 部分和 map
函数部分。
首先,~ starwars %>% count(.x))
是 shorthand 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 认为 .x
是 starwars
.
中的列
尝试 2/3:count()
/ group_by()
期望符号而不是字符输入。
!!
将 .x
替换为“eye_color”。但是“eye_color”不是symbol/name而是一个字符。
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
函数的一种比较直观的方法是传递 symbols/names 并使用 {{.x}}
来评估承诺。 (不那么直观,你可以做 !!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 的解决方案更适合您的问题。
但是你可以如下使用地图
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), ...)
的缩写,因此与 python 中的 enumerate()
不同。有像 seq_along
这样的 R 函数,它可以给你在对象中的位置,但我没有将它们与地图一起使用。
你能帮我理解准报价的工作原理吗? 我正在使用地图和计数功能,但它似乎无法正常工作。
第一次尝试:
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]] ="
我认为这个问题可以分解为 quasi-quotation 部分和 map
函数部分。
首先,~ starwars %>% count(.x))
是 shorthand 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 认为 .x
是 starwars
.
尝试 2/3:count()
/ group_by()
期望符号而不是字符输入。
!!
将 .x
替换为“eye_color”。但是“eye_color”不是symbol/name而是一个字符。
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
函数的一种比较直观的方法是传递 symbols/names 并使用 {{.x}}
来评估承诺。 (不那么直观,你可以做 !!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 的解决方案更适合您的问题。
但是你可以如下使用地图
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), ...)
的缩写,因此与 python 中的 enumerate()
不同。有像 seq_along
这样的 R 函数,它可以给你在对象中的位置,但我没有将它们与地图一起使用。