DT [!(x ==。)]和DT [x!=。]不一致地处理x中的NA

时间:2013-04-26 14:41:03

标签: r dataframe data.table

这是我认为我应该问this question之后的事情。我想在R-forge跟踪器中将其作为一个错误/不一致之前确认是否存在错误/不一致。

考虑这个data.table

require(data.table)
DT <- data.table(x=c(1,0,NA), y=1:3)

现在,要访问 0的DT的所有行,我们可以通过以下方式进行:

DT[x != 0]
#    x y
# 1: 1 1
DT[!(x == 0)]
#     x y
# 1:  1 1
# 2: NA 3

当基础逻辑操作相同时,访问DT[x != 0]DT[!(x==0)]会产生不同的结果。

注意:将其转换为data.frame并运行这些操作将为逻辑上等效的操作提供彼此相同的结果,但结果不同从这两个data.table结果。有关原因的说明,请查看?`[`部分下的NAs in indexing

编辑:由于你们中有些人强调要与data.frame平等,这里是data.frame上相同操作输出的片段:

DF <- as.data.frame(DT)
# check ?`[` under the section `NAs in indexing` as to why this happens
DF[DF$x != 0, ]
#     x  y
# 1   1  1
# NA NA NA
DF[!(DF$x == 0), ]
#     x  y
# 1   1  1
# NA NA NA

我认为这是不一致的,应该提供相同的结果。但是,结果呢? [.data.table的文档说:

  

i ---&gt;整数,逻辑或字符向量,列名,列表或data.table的表达式。

     

整数和逻辑向量的工作方式与它们在[.data.frame中的工作方式相同。 除了逻辑i中的NAs被视为FALSE ,并且单个NA逻辑不会被回收以匹配行数,因为它在[.data.frame。

中。

很清楚为什么结果与在data.frame上执行相同操作所获得的结果不同。但是,在data.table中,如果是这种情况,那么它们都应该返回:

#    x y
# 1: 1 1

我浏览了[.data.table源代码,现在了解为什么这种情况正在发生。有关为何发生这种情况的详细说明,请参阅this post

简而言之,x != 0评估为“逻辑”,NA被替换为FALSE。但是,!(x==0),第一个(x == 0)被评估为逻辑,NA被替换为FALSE。 然后发生否定,导致NA基本上成为TRUE

所以,我的第一个(或者说是主要的)问题是,这是一个错误/不一致吗?如果是这样,我会在data.table R-forge跟踪器中将其归档为一个。如果没有,我想知道这种差异的原因,我想建议对文件进行修正,解释这种差异(对于已经很棒的文档!)。

修改跟进评论后,第二个问题是,data.table通过使用包含NA的列进行索引来进行子集化的处理方式是否应与data.frame类似} ?? (但我同意,在@Roland的评论之后,这个可能很好地引出了意见,我完全没有回答这个问题。)

4 个答案:

答案 0 :(得分:7)

我认为这是记录在案且行为一致的。

需要注意的主要事项是!参数中的前缀i是非联接的标志,因此x != 0!(x==0)不再相同逻辑运算处理data.table中记录的NA处理

有关not join

的新闻部分
A new "!" prefix on i signals 'not-join' (a.k.a. 'not-where'), #1384i.
            DT[-DT["a", which=TRUE, nomatch=0]]   # old not-join idiom, still works
            DT[!"a"]                              # same result, now preferred.
            DT[!J(6),...]                         # !J == not-join
            DT[!2:3,...]                          # ! on all types of i
            DT[colA!=6L | colB!=23L,...]          # multiple vector scanning approach (slow)
            DT[!J(6L,23L)]                        # same result, faster binary search
        '!' has been used rather than '-' :
            * to match the 'not-join'/'not-where' nomenclature
            * with '-', DT[-0] would return DT rather than DT[0] and not be backwards
              compatible. With '!', DT[!0] returns DT both before (since !0 is TRUE in
              base R) and after this new feature.
            * to leave DT[+J...] and DT[-J...] available for future use

来自?data.table

  

所有类型的'i'都可能以!为前缀。这表示未加入或   应该执行not-select。纵观data.table文档,   我们指的是'i'的类型,我们指的是'i'之后的类型   '!',如果有的话。见例子。


为什么它与data.table中记录的NA处理一致

NA值被视为FALSE。可以把它想象成对每个元素执行isTRUE

所以DT[x!=0]TRUE FALSE NA编入索引,由于记录的NA处理而变为TRUE FALSE FALSE

当事情为真时,你想要分组。

这意味着您将获得x!= 0为TRUE(而非NA)的那些

DT[!(x==0)]使用 not join 状态,您希望所有非0的内容(可以包括NA值)。


跟进查询/进一步的例子

DT[!(x!=0)]

## returns
    x y
1:  0 2
2: NA 3
对于一个值,

x!=0为TRUE,因此not join将返回不正确的值。 (即FALSE(实际为== 0)或NA

DT[!!(x==0)]

## returns
    x y
1:  0 2
2: NA 3

这被解析为!(!(x==0))。前缀!表示非连接,内部!(x==0)的解析与x!=0相同,因此上述情况的推理适用。

答案 1 :(得分:3)

我这个讨论迟了一个月,但是用新的眼睛阅读所有的评论...是的,如果DT[x != .]中包含NA的任何行,我认为x会更好结果,我们应该改变它。

从另一个角度进一步加入背景问题后,新答案又添加到链接问题中:

https://stackoverflow.com/a/17008872/403310

答案 2 :(得分:3)

version 1.8.11 开始,!不会触发逻辑表达式的非连接,并且两个表达式的结果相同:

DT <- data.table(x=c(1,0,NA), y=1:3)
DT[x != 0]
#   x y
#1: 1 1
DT[!(x == 0)]
#   x y
#1: 1 1

@ mnel的答案中提到的其他几个表达现在也表现得更加可预测:

DT[!(x != 0)]
#   x y
#1: 0 2
DT[!!(x == 0)]
#   x y
#1: 0 2

答案 3 :(得分:0)

我的观点是subset做了正确的事,而data.tabledata.frame都做不到,data.frame做了最愚蠢的事。所以,就你的问题而言 - 不,我不认为data.table应该与data.frame做同样的事情,它应该与subset做同样的事情。

对于记录,这是subset

的输出
subset(DF, x != 0)
#  x y
#1 1 1
subset(DF, !(x == 0))
#  x y
#1 1 1
#
# or if you want the NA's as well
subset(DF, is.na(x) | x != 0)
#   x y
#1  1 1
#3 NA 3

我想详细说明为什么data.frame输出是愚蠢的。 [.data.frame描述中的第一行说明 - “提取或替换数据框的子集”。它返回的输出,其中有一行rowname = NA且所有元素都等于NA,它们不属于给定数据帧的“子集”,使得输出与功能的含义。从用户的角度来看,这也是一个巨大的麻烦,因为必须始终了解这些事情并找到解决此问题的方法。

data.table输出而言 - 它显然是不一致的,但至少不那么愚蠢,因为在这两种情况下它实际上都会返回原始数据表的子集。