问题
I have run across a situation where %>%
produces very surprising output when combined with !
. Consider the following code:
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
Ok, nothing surprising there. But if I try to shorten it using %>%
weird stuff happens:
!is.na(x) %>% sum
[1] TRUE
TRUE
?? Not what I expected - it should be 20
.
If I remove the !
it gives me 0
as expected:
> is.na(x) %>% sum
[1] 0
and if I add brackets it works:
> {!is.na(x)} %>% sum
[1] 20
and treating !
as a function works:
> is.na(x) %>% `!` %>% sum
[1] 20
What is !is.na(x) %>% sum
doing, and why does it return TRUE
rather than 20
?
EDIT: The other logical operators produce similar behavior:
> T&T %>% sum()
[1] TRUE
> {T&T} %>% sum()
[1] 1
> T|T %>% sum()
[1] TRUE
> {T|T} %>% sum()
[1] 1
回答1:
I suspect that it's an order of operations issue:
!is.na(x) %>% sum
is evaluating to
!(is.na(x) %>% sum)
Which is equivalent to TRUE
回答2:
Although I accepted @C-Z_ 's answer I want to add another to provide context on this. Thanks to @rawr for directing me to ?Syntax
.
Basically %>%
is considered to be an operator, like %in%
and as such it has to obey the order of operations. On the Syntax
help page this corresponds to the %any%
operator (i.e. any infix operator), as users can define these at will. As it happens, this means that %>%
fires before any logical operator and also before arithmetic operators (e.g. *
and \
). As a result, if you are naively, like I was, thinking that the left side of %>%
will complete before the next step in the chain, you can get some surprises. For example:
3+2 %>% '*'(4) %>% `/`(2)
Does not do 3+2=5, 5*4= 20, 20/2=10
instead it does 2*4/2=4, 4+3=7
, because the %>%
has precedence over +
.
If you use the functions in the magrittr
package such as:
add(3,2) %>% multiply_by(4) %>% divide_by(2)
You get 10
as expected. Placing brackets around the 3+2
will also get you 10
.
In my original examples, the logical operators, such as !
have a lower precedence than %>%
, so they act last, after the sum has competed.
Moral of the story: Be careful mixing %>%
with other operators.
回答3:
You can also use the "not" alias from the magrittr package:
> is.na(1:20) %>% not %>% sum
[1] 20
来源:https://stackoverflow.com/questions/37732820/use-of-or-any-logical-operator-with-magrittr-produces-unexpected-outpu