我在一个关于大型数据帧的复杂语句中偶然发现了dplyr::filter
的行为,这基本上归结为NA
值的处理:
df <- tibble(a = c(rep(1,3),
rep(NA, 3)))
A tibble: 6 x 1
a
<dbl>
1 1
2 1
3 1
4 NA
5 NA
6 NA
过滤等于1的行会得到预期的结果:
df %>% filter(a == 1)
A tibble: 3 x 1
a
<dbl>
1 1
2 1
3 1
对不等于1的行进行过滤,我希望返回剩下的3行df,但情况并非如此:
df %>% filter(!a == 1)
A tibble: 0 x 1
... with 1 variables: a <dbl>
因此,在第一种情况下,NA
被解释为不等于1,在第二种情况下,它被解释为等于1.是否存在我在这里缺少的逻辑?
我知道我可以使用%in%
来获得预期的结果:
df %>% filter(!a %in% 1)
A tibble: 3 x 1
a
<dbl>
1 NA
2 NA
3 NA
但是我觉得使用这个运算符只有一个元素(而不是一个向量)似乎很奇怪。
所以我向专家提问:这是filter
的预期行为吗?在否定过滤条件时使用%in%
是否常见?
答案 0 :(得分:4)
这是由于%in%
的行为,而不是filter
。
让我们使用一个简单的例子:
a = c(1, 1, 1, NA, NA, NA)
> a == 1
[1] TRUE TRUE TRUE NA NA NA
> a != 1
[1] FALSE FALSE FALSE NA NA NA
> !(a == 1)
[1] FALSE FALSE FALSE NA NA NA
我们看到当我们使用关系运算符==
或!=
时,输入中的NA值在输出中保持为NA。然而...
> a %in% 1
[1] TRUE TRUE TRUE FALSE FALSE FALSE
> !(a %in% 1)
[1] FALSE FALSE FALSE TRUE TRUE TRUE
使用%in%
运算符,输入中的NA值在输出中变为FALSE。由于这应该是match()
更直观的界面,让我们来看看它:
> match(a, 1)
[1] 1 1 1 NA NA NA
所以不,match()
本身并不是这样做的,至少不是默认参数。但是,帮助文件?match
解释了:
%in%
目前定义为
"%in%" <- function(x, table) match(x, table, nomatch = 0) > 0
你有它。当我们使用a %in% 1
时,我们实际上正在执行以下操作:
> match(a, 1, nomatch = 0L)
[1] 1 1 1 0 0 0
> match(a, 1, nomatch = 0L) > 0L
[1] TRUE TRUE TRUE FALSE FALSE FALSE
因此,当filter()
运算符与%in%
否定一起使用时,!
会返回带有NA值的行。