我在数据表中有一列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)
我可以使用J()
函数查找x
列等于.2的所有实例。
> 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]
答案 0 :(得分:3)
更新:这已经在v1.9.2中修复了一段时间。来自NEWS:
NA
,NaN
,+Inf
和-Inf
现在被视为不同的值,可以在键中,可以加入并可以分组。 data.table定义:NA&lt; NaN&lt; -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的几个问题以及listserv在data.table
密钥中探索NA的一些电子邮件。
FAQ中列出的主要观点是NA
被视为FALSE
http://r.789695.n4.nabble.com/Follow-up-on-subsetting-data-table-with-NAs-td4669097.html
subsetting a data.table using !=<some non-NA> excludes NA too
NA in `i` expression of data.table (possible bug)
DT[!(x == .)] and DT[x != .] treat NA in x inconsistently
与此同时,您最好的选择是使用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)
答案 1 :(得分:3)
这是一个快速的解决方法,它很大程度上依赖于内部实际发生的事情(使代码变得有点脆弱)。因为内部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)]
答案 2 :(得分:0)
看看这是否有用。
my.dt[!is.finite(x),]
x y
1: NaN 2
2: NaN 4
3: NaN 6