我偶然发现了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
Run Code Online (Sandbox Code Playgroud)
过滤等于 1 的行可得到预期结果:
df %>% filter(a == 1)
A tibble: 3 x 1
a
<dbl>
1 1
2 1
3 1
Run Code Online (Sandbox Code Playgroud)
过滤不等于 1 的行,我希望返回 df 的剩余 3 行,但事实并非如此:
df %>% filter(!a == 1)
A tibble: 0 x 1
... with 1 variables: a <dbl>
Run Code Online (Sandbox Code Playgroud)
因此,虽然在第一种情况下NA被解释为不等于 1,但在第二种情况下,它被解释为等于 1。我在这里缺少逻辑吗?
我知道我可以用它%in%来获得预期的结果:
df %>% filter(!a %in% 1)
A tibble: 3 x 1
a
<dbl>
1 NA
2 NA
3 NA
Run Code Online (Sandbox Code Playgroud)
但对我来说,仅将这个运算符与一个元素(而不是向量)一起使用似乎很奇怪。
所以我向专家提出的问题是:这是预期的行为吗filter?%in%否定过滤条件时使用常见做法吗?
这是由于 的行为造成的%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
Run Code Online (Sandbox Code Playgroud)
我们看到,当我们使用关系运算符==或时!=,输入中的 NA 值在输出中仍然是 NA。然而...
> a %in% 1
[1] TRUE TRUE TRUE FALSE FALSE FALSE
> !(a %in% 1)
[1] FALSE FALSE FALSE TRUE TRUE TRUE
Run Code Online (Sandbox Code Playgroud)
使用该%in%运算符,输入中的 NA 值在输出中将变为 FALSE。由于这应该是 的更直观的界面match(),所以我们也看一下:
> match(a, 1)
[1] 1 1 1 NA NA NA
Run Code Online (Sandbox Code Playgroud)
所以不,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
Run Code Online (Sandbox Code Playgroud)
因此,filter()当该%in%运算符与否定一起使用时,将返回具有 NA 值的行!。