R中的“ pipe”,“ dot”和“ dollar”运算符的串联似乎如何工作?

时间:2019-12-29 03:40:44

标签: r dplyr magrittr

请参见下面的代码行; 谋杀是一个包含变量/列总数人口比率的数据框:

r <- murders %>% summarize (rate = sum(total) / sum(population) * 10^6) %>% .$rate

在这种情况下,操作员%>%.$的工作情况如何?有人可以详细说明吗?

编辑:我知道这行代码的结果(它提取了 rate 列),但是想知道为什么会发生或如何发生,因为通常遵循%>%通过一个函数,即使我们将$运算符视为一个函数,它也不会在%>%之后立即启动,而是在两者之间存在.。如果我们说.%>%函数中$输出的占位符,那么%>%$也应该起作用,因为%>%的输出,默认情况下自动自动进入RHS函数的第一个参数(在我们的示例中为$),在这种情况下不需要.

2 个答案:

答案 0 :(得分:1)

在这种情况下,它等效于pull

最小示例

最开始的一个实际工作示例非常好。我建议在以后的问题中至少提供那么多。

library(dplyr)
murders <- data.frame('loc'=c('A','B','C'), 
                      'population'=c(10,20,30),
                      'total'=c(2,3,5))

result <- murders %>% 
          summarize (rate = sum(total) / sum(population) * 10^6) %>%
          .$rate

result # 166666.7

上面示例中的.result of the previous pipe。美元符号是提取运算符,它将返回名为rate的列。

等效示例

pull函数正在将管道的结果传递到第一个arg中。在这种情况下,由于pull的作用与提取($)相同,因此发生的事情更加明确。

result_2 <- murders %>% 
            summarize (rate = sum(total) / sum(population) * 10^6) %>% 
            pull(rate)

result_2 # 166666.7

您可以通过以下操作说明这一点

result_3 <- murders %>% 
            summarize (rate = sum(total) / sum(population) * 10^6) %>% 
            pull(.data=., var=rate)

result_3 # 166666.7

将管道移至$[[无效

短故事,$[[是基元,magrittr %>% works with functions

  

将对象转发到函数或调用表达式中。

     

lhs%>%rhs

     

参数lhs

     

一个值或magrittr占位符。 rhs

     

使用magrittr语义的函数调用。

`$` # .Primitive("$")
`[[` # .Primative{"[[")

近似函数pullgetElement是函数

`getElement`
# function (object, name) 
# {
#     if (isS4(object)) 
#         methods::slot(object, name)
#     else object[[name, exact = TRUE]]
# }
# <bytecode: 0x5618b3018358>
# <environment: namespace:base> 

答案 1 :(得分:1)

烟斗和美元

foo$bar表示法解析为等效于`$`(foo, bar),其中$是一个函数。

此函数是原始函数这一事实与此处的作用完全无关。

以这个例子为例:

df <- data.frame(a=1:2, b = 3:4)
df
#>   a b
#> 1 1 3
#> 2 2 4

由于运算符$的优先级高于%>%的优先级(请参见?Syntax),因此以下等价:

df %>% .$a
#> [1] 1 2
df %>% (.$a)
#> [1] 1 2
df %>% `$`(., a)
#> [1] 1 2

实际上, magrittr 甚至无法“看到”前者和后者之间的区别。

然后由于magrittr的语义以及$的R语法,以下是等效的:

df %>% `$`(., a)
#> [1] 1 2
`$`(df, a)
#> [1] 1 2
df$a
#> [1] 1 2

评论者对df %>% $a不起作用感到惊讶,原因是 magrittr 无法操作任何魔术,如果语法不正确,则解析器将在调用任何函数之前阻塞!

这使我们为最后一部分做好了准备,因为df %>% +1是正确的语法,所以 magrittr 会做什么?

其他运算符?

如果我们回到?syntax,我们会发现我们还有其他优先于%>%的二进制运算符::::::@,{ {1}},[[[

我们无法对:::(默认定义)使用相同的技巧,因为它们使用正则表达式,因此 magrittr 不会向它们提供适当的第一个参数,但是我们可以和其他参数一起玩:

:::

3 %>% .:5 #> [1] 3 4 5 df %>% .["a"] #> a #> 1 1 #> 2 2 +的特例

-+符号具有特殊性,以一元(-)或二进制(+1)形式使用时,它们具有不同的优先级,并且一元形式的优先级高于1+2

由于解析器允许一元形式,%>%是正确的语法,等效于df %>% +1,因此magrittr然后像在任何函数上一样在df %>% `+`(1)上应用其魔力,并添加了一个隐式点占位符作为第一个参数,因此以下调用是等效的:

+

如果要在 ggplot2 中使用管道,可以使用此古怪的属性:

df %>% +1       # unary '+'
df %>% `+`(1)   # unary '+'
df %>% `+(.,1)` # binary '+' !!!
`+`(df,1)       # binary '+' !!!
df + 1          # binary '+' !!!

后一个调用可以直接通过管道传递到另一个函数中,例如library(ggplot2) cars %>% ggplot(aes(speed, dist)) + geom_point() # equivalent cars %>% ggplot(aes(speed, dist)) %>% +geom_point() saveRDS(),而前一个则不能。