5

我在数据表中有一个包含NaN值的列。就像是:

my.dt <- data.table(x = c(NaN, NaN, NaN, .1, .2, .2, .3), y = c(2, 4, 6, 8, 10, 12, 14))
setkey(my.dt, x)

我可以使用该函数查找列等于 .2J()的所有实例x

> my.dt[J(.2)]

     x  y
1: 0.2 10
2: 0.2 12

但是如果我尝试用NaN它做同样的事情是行不通的。

> my.dt[J(NaN)]

     x  y
1: NaN NA

我希望:

     x  y
1: NaN  2
2: NaN  4
3: NaN  6

是什么赋予了?我在 data.table 文档中找不到任何东西来解释为什么会发生这种情况(尽管可能只是我不知道要寻找什么)。有什么办法可以得到我想要的吗?最终,我想NaN用零替换所有值,使用类似的东西my.dt[J(NaN), x := 0]

4

3 回答 3

3

更新:这已在 v1.9.2 中修复了一段时间。来自新闻

NA, NaN,+Inf-Inf现在被认为是不同的值,可以在键中,可以加入并可以分组。data.table 定义:NA < NaN < -Inf。感谢 Martin Liberts 的建议,#4684、#4815 和 #4883。

require(data.table) ## 1.9.2+
my.dt[J(NaN)]
#      x  y
# 1: NaN  2
# 2: NaN  4
# 3: NaN  6

这个问题是部分设计选择,部分错误。有几个关于 SO 的问题和一些关于列表服务器的电子邮件,探讨了 NA 的data.table关键。

主要思想在常见问题解答中概述,NA被视为FALSE

请随时加入邮件列表中的对话。@Arun 发起了一个对话,

http://r.789695.n4.nabble.com/Follow-up-on-subsetting-data-table-with-NAs-td4669097.html

此外,您可以在 SO 上以下任何问题的答案和评论中阅读更多内容:

使用 !=<some non-NA> 对 data.table 进行子集化会在 data.table
的 `i` 表达式中排除 NA 和 NA(可能的错误)
DT[!(x == .)] 和 DT[x!= .] 对待x中的NA不一致


与此同时,您最好的选择是使用is.na.
虽然它比基数搜索慢,但它仍然比 中的大多数矢量搜索快R,而且肯定比任何花哨的解决方法快得多

library(microbenchmark)
microbenchmark(my.dt[.(1)], my.dt[is.na(ID)], my.dt[ID==1], my.dt[!!!(ID)])
# Unit: milliseconds
               expr    median 
        my.dt[.(1)]  1.309948 
   my.dt[is.na(ID)]  3.444689   <~~ Not bad
     my.dt[ID == 1]  4.005093 
 my.dt[!(!(!(ID)))] 10.038134 

### using the following for my.dt
my.dt <- as.data.table(replicate(20, sample(100, 1e5, TRUE)))
setnames(my.dt, 1, "ID")
my.dt[sample(1e5, 1e3), ID := NA]
setkey(my.dt, ID)
于 2013-10-08T05:00:44.030 回答
3

这是一个快速的解决方法,它在很大程度上依赖于内部实际发生的事情(使代码有点脆弱 imo)。因为内部NaN只是一个非常非常负的数字,所以它总是在你的data.table前面setkey。我们可以使用该属性来隔离这些条目,如下所示:

# this will give the index of the first element that is *not* NaN
my.dt[J(-.Machine$double.xmax), roll = -Inf, which = T]

# this is equivalent to my.dt[!is.nan(x)], but much faster
my.dt[seq_len(my.dt[J(-.Machine$double.xmax), roll = -Inf, which = T] - 1)]

这是里卡多样本数据的基准:

my.dt <- as.data.table(replicate(20, sample(100, 1e5, TRUE)))
setnames(my.dt, 1, "ID")
my.dt[sample(1e5, 1e3), ID := NA]
setkey(my.dt, ID)

# NOTE: I have to use integer max here - because this example has integers
# instead of doubles, so I'll just add simple helper function (that would
# likely need to be extended for other cases, but I'm just dealing with the ones here)
minN = function(x) if (is.integer(x)) -.Machine$integer.max else -.Machine$double.xmax

library(microbenchmark)
microbenchmark(normalJ = my.dt[J(1)],
               naJ = my.dt[seq_len(my.dt[J(minN(ID)), roll = -Inf, which = T] - 1)])
#Unit: milliseconds
#    expr      min       lq   median       uq       max neval
# normalJ 1.645442 1.864812 2.120577 2.863497  5.431828   100
#     naJ 1.465806 1.689350 2.030425 2.600720 10.436934   100

在我的测试中,以下minN函数还涵盖了字符和逻辑向量:

minN = function(x) {
  if (is.integer(x)) {
    -.Machine$integer.max
  } else if (is.numeric(x)) {
    -.Machine$double.xmax
  } else if (is.character(x)) {
    ""
  } else if (is.logical(x)) {
    FALSE
  } else {
    NA
  }
}

你会想要添加mult = 'first',例如:

my.dt[seq_len(my.dt[J(minN(colname)), roll = -Inf, which = T, mult = 'first'] - 1)]
于 2013-10-08T16:06:44.453 回答
0

看看这是否有帮助。

my.dt[!is.finite(x),]
     x y
1: NaN 2
2: NaN 4
3: NaN 6
于 2013-10-08T03:10:58.077 回答