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

Aru*_*run 21 r dataframe data.table

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

考虑一下data.table:

require(data.table)
DT <- data.table(x=c(1,0,NA), y=1:3)
Run Code Online (Sandbox Code Playgroud)

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

DT[x != 0]
#    x y
# 1: 1 1
DT[!(x == 0)]
#     x y
# 1:  1 1
# 2: NA 3
Run Code Online (Sandbox Code Playgroud)

当基础逻辑操作等效时,访问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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

#    x y
# 1: 1 1
Run Code Online (Sandbox Code Playgroud)

我浏览了[.data.table源代码,现在了解为什么会发生这种情况.有关发生这种情况的原因的详细说明,请参阅 此文章.

简而言之,x != 0评估为"逻辑" NA并被替换为FALSE.但是,!(x==0)首先(x == 0)将其评估为逻辑,然后NA替换为FALSE.然后发生否定,这导致NA基本上变成了TRUE.

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

编辑:跟着评论,第二个问题是,应该data.table通过索引来处理子集,其中列包含NA类似于data.frame??的列.(但我同意,在@Roland的评论之后,这可能会很好地引出意见,我完全没有回答这个问题).

mne*_*nel 7

我认为这是记录和一致的行为.

需要注意的主要问题是,前缀 !的内部i参数是一个标志为不加入,所以x != 0!(x==0)不再是同一逻辑运算与NA的内data.table的文档处理工作时

关于该消息的新闻部分 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
Run Code Online (Sandbox Code Playgroud)

来自 ?data.table

所有类型的'i'都可以以!为前缀.这表示应该执行非连接或非选择.在整个data.table文档中,我们引用'i'的类型,我们指的是'!'之后的'i'类型,如果存在的话.见例子.


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

NA值被视为FALSE.可以把它想象成isTRUE每个元素.

所以DT[x!=0]被索引与TRUE FALSE NA成为TRUE FALSE FALSE由于记录NA处理.

当事情是真的时,你想要分组.

这意味着你得到x!= 0为TRUE(而不是NA)的那些

DT[!(x==0)]使用非连接状态,你想要的一切都不是0(可以包括NA值).


跟进查询/进一步的例子

DT[!(x!=0)]

## returns
    x y
1:  0 2
2: NA 3
Run Code Online (Sandbox Code Playgroud)

x!=0对于一个值为TRUE,因此not join将返回不正确的值.(即FALSE(实际上== 0)或NA

DT[!!(x==0)]

## returns
    x y
1:  0 2
2: NA 3
Run Code Online (Sandbox Code Playgroud)

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

  • 这个*怎么没有记录?它是在帮助中(相关部分添加到这个答案和新闻中.使用前导`(`来阻止不连接被触发*是*这是一个很好的方式 - 也许可以明确记录因此(使用`()`juidiciously正在成为[data.table idiom](http://stackoverflow.com/questions/16191083/subset-data-table-by-logical-column/16191749#comment23149196_16191749) (2认同)

edd*_*ddi 4

版本 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
Run Code Online (Sandbox Code Playgroud)

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

DT[!(x != 0)]
#   x y
#1: 0 2
DT[!!(x == 0)]
#   x y
#1: 0 2
Run Code Online (Sandbox Code Playgroud)