用于 ! (或任何逻辑运算符)与 %>% (magrittr) 产生意外输出

Use of ! (or any logical operator) with %>% (magrittr) produces unexpected output

我有 运行 遇到 %>%! 结合时产生非常令人惊讶的输出的情况。考虑以下代码:

x <- c(1:20)
y <- !is.na(x)

> y
 [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
     TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE

> sum(Y)
[1] 20

好的,没什么奇怪的。但是,如果我尝试使用 %>% 来缩短它,就会发生奇怪的事情:

!is.na(x) %>% sum

[1] TRUE

TRUE??不是我所期望的 - 它应该是 20

如果我删除 !,它会给我预期的 0

> is.na(x) %>% sum
[1] 0

如果我添加方括号,它会起作用:

> {!is.na(x)} %>% sum
[1] 20

并将 ! 视为函数有效:

> is.na(x) %>% `!` %>% sum
[1] 20

!is.na(x) %>% sum 在做什么,为什么 return TRUE 而不是 20

编辑: 其他逻辑运算符产生类似的行为:

> T&T %>% sum()
[1] TRUE
> {T&T} %>% sum()
[1] 1

> T|T %>% sum()
[1] TRUE
> {T|T} %>% sum()
[1] 1

我怀疑是操作顺序问题:

!is.na(x) %>% sum

正在评估

!(is.na(x) %>% sum)

相当于TRUE

尽管我接受了@C-Z_ 的回答,但我想添加另一个来提供相关背景信息。感谢@rawr 指引我前往 ?Syntax.

基本上 %>% 被认为是一个操作符,就像 %in% 一样,因此它必须遵守操作顺序。在 Syntax 帮助页面上,这对应于 %any% 运算符(即任何中缀运算符),因为用户可以随意定义它们。碰巧的是,这意味着 %>% 在任何逻辑运算符之前触发,也在算术运算符(例如 *\ )之前触发。因此,如果您像我一样天真地认为 %>% 的左侧将在链中的下一步之前完成,您会得到一些惊喜。例如:

3+2 %>% '*'(4) %>% `/`(2)

不做3+2=5, 5*4= 20, 20/2=10

而不是 2*4/2=4, 4+3=7,因为 %>% 优先于 +

如果使用magrittr包中的函数如:

add(3,2) %>% multiply_by(4) %>% divide_by(2) 

您得到了预期的 10。在 3+2 周围放置方括号也会得到 10.

在我原来的例子中,逻辑运算符,例如 ! 的优先级低于 %>%,因此它们最后执行,在求和完成后。

故事的寓意:小心将 %>% 与其他运算符混合使用。

您还可以使用 magrittr 包中的 "not" 别名:

> is.na(1:20) %>% not %>% sum

[1] 20