在对数据框进行子集操作时,NA表现出了意外的行为

18
考虑以下代码。当您在条件中不显式测试NA时,该代码将在稍后的日期失败,然后您的数据发生更改。
>   # A toy example
>   a <- as.data.frame(cbind(col1=c(1,2,3,4),col2=c(2,NA,2,3),col3=c(1,2,3,4),col4=c(4,3,2,1)))
>   a
  col1 col2 col3 col4
1    1    2    1    4
2    2   NA    2    3
3    3    2    3    2
4    4    3    4    1
>   
>   # Bummer, there's an NA in my condition
>   a$col2==2
[1]  TRUE    NA  TRUE FALSE
> 
>   # Why is this a good thing to do?
>   # It NA'd the whole row, and kept it
>   a[a$col2==2,]
   col1 col2 col3 col4
1     1    2    1    4
NA   NA   NA   NA   NA
3     3    2    3    2
>   
>   # Yes, this is the right way to do it
>   a[!is.na(a$col2) & a$col2==2,]
  col1 col2 col3 col4
1    1    2    1    4
3    3    2    3    2
>     
>   # Subset seems designed to avoid this problem
>   subset(a, col2 == 2)
  col1 col2 col3 col4
1    1    2    1    4
3    3    2    3    2

能否有人解释一下为什么没有 is.na 检查得到的行为会是好的或有用的?

1个回答

33
我完全同意这不是直观的(我之前在SO上提到过这一点)。为了维护R,我认为知道何时存在缺失值是有用的(即这不是一个错误)。操作符==明确地设计成通知用户NA或NaN值。更多信息请参见?"=="。它说明:

缺失值('NA')和'NaN'值被视为不可比较,即使对于它们自己也是如此,因此涉及它们的比较将始终导致'NA'。

换句话说,使用二进制运算符无法比较缺失值(因为它是未知的)。
除了is.na()之外,您还可以执行:
which(a$col2==2) # tests explicitly for TRUE

或者

a$col2 %in% 2 # only checks for 2

%in%被定义为使用match()函数:

'"%in%" <- function(x, table) match(x, table, nomatch = 0) > 0'

这也在"The R Inferno"中有提到。

在R中检查数据中的NA值是非常关键的,因为许多重要的运算符并不像你期望的那样处理它。除了==之外,&,|,<,sum()等都是如此。当我编写R代码时,我总是在想“如果这里有NA会发生什么”。要求R用户小心处理缺失值是“有意设计”的。

更新:当有多个逻辑条件时,如何处理NA?

NA是一个逻辑常量,如果不考虑可能返回的结果(例如NA | TRUE == TRUE),则可能会得到意外的子集。这些来自?Logic的真值表可能会提供有用的说明:

outer(x, x, "&") ## AND table
#       <NA> FALSE  TRUE
#<NA>     NA FALSE    NA
#FALSE FALSE FALSE FALSE
#TRUE     NA FALSE  TRUE

outer(x, x, "|") ## OR  table
#      <NA> FALSE TRUE
#<NA>    NA    NA TRUE
#FALSE   NA FALSE TRUE
#TRUE  TRUE  TRUE TRUE

这是一个非常棒的答案。 - Andrew Brēza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接