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)

関数を使用して、列が .2 に等しいJ()すべてのインスタンスを見つけることができます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

これは、内部で実際に起こっていることに大きく依存する迅速な回避策です(コードが少し壊れやすいものになります)。内部的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)]

Ricardo のサンプル データのベンチマークは次のとおりです。

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 に答える