子集 data.frame 中的 NA 会做一些意想不到的事情

An NA in subsetting a data.frame does something unexpected

提问人:Craig Schmidt 提问时间:11/21/2009 最后编辑:Ben BolkerCraig Schmidt 更新时间:10/18/2013 访问量:4012

问:

请考虑以下代码。如果未在条件中显式测试,则该代码将在以后的某个日期失败,然后数据会更改。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

r

评论


答:

33赞 Shane 11/21/2009 #1

我绝对同意这并不直观(我之前在 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

评论

0赞 Andrew Brēza 7/16/2022
这是一个了不起的答案