web-dev-qa-db-ja.com

Rのdata.tableでNAを選択します

データテーブルの主キーに値が欠落しているすべての行を選択するにはどうすればよいですか。

DT = data.table(x=rep(c("a","b",NA),each=3), y=c(1,3,6), v=1:9)
setkey(DT,x)   

特定の値を選択するのは簡単です

DT["a",]  

欠落している値を選択するには、ベクトル検索が必要なようです。二分探索は使えません。私は正しいですか?

DT[NA,]# does not work
DT[is.na(x),] #does work
23
Farrel

幸い、DT[is.na(x),]は(例)DT["a",]とほぼ同じ速度であるため、実際には、これはそれほど重要ではない可能性があります。

library(data.table)
library(rbenchmark)

DT = data.table(x=rep(c("a","b",NA),each=3e6), y=c(1,3,6), v=1:9)
setkey(DT,x)  

benchmark(DT["a",],
          DT[is.na(x),],
          replications=20)
#             test replications elapsed relative user.self sys.self user.child
# 1      DT["a", ]           20    9.18    1.000      7.31     1.83         NA
# 2 DT[is.na(x), ]           20   10.55    1.149      8.69     1.85         NA

===

マシューからの追加(コメントには収まりません):

ただし、上記のデータには3つの非常に大きなグループがあります。したがって、ここでは、バイナリ検索の速度の利点は、大きなサブセットを作成する時間によって支配されます(データの1/3がコピーされます)。

benchmark(DT["a",],  # repeat select of large subset on my netbook
    DT[is.na(x),],
    replications=3)
          test replications elapsed relative user.self sys.self
     DT["a", ]            3   2.406    1.000     2.357    0.044
DT[is.na(x), ]            3   3.876    1.611     3.812    0.056

benchmark(DT["a",which=TRUE],   # isolate search time
    DT[is.na(x),which=TRUE],
    replications=3)
                      test replications elapsed relative user.self sys.self
     DT["a", which = TRUE]            3   0.492    1.000     0.492    0.000
DT[is.na(x), which = TRUE]            3   2.941    5.978     2.932    0.004

返されるサブセットのサイズが小さくなると(たとえば、グループを追加するなど)、違いが明らかになります。 1つの列でのベクトルスキャンはそれほど悪くはありませんが、2つ以上の列ではすぐに劣化します。

たぶんNAは参加可能でなければなりません。でも、それについての落とし穴を覚えているようです。 FR#1043キーのNAを許可または禁止しますか? からリンクされたいくつかの履歴があります。そこには、NA_integer_が内部的に負の整数であることが記載されています。これにより、基数/カウントソート(iirc)がトリップし、setkeyの速度が低下します。しかし、それは再訪するリストにあります。

22
Josh O'Brien

これは現在、v1.8.11で実装されています。 [〜#〜] news [〜#〜] から

oバイナリ検索で、NA/NaNsをサブセット化できるようになりました。また、joinss/mergessを照合することで、NANaNを実行できます。

現時点では、正しいNANA_real_NA_character_など)を明示的に指定する必要がありますが。

OPのデータについて:

DT[J(NA_character_)] # or for characters simply DT[NA_character_]
#     x y v
# 1: NA 1 7
# 2: NA 3 8
# 3: NA 6 9

また、@ JoshOBrienの投稿からの同じベンチマークに、NAのこのバイナリ検索が追加されています。

library(data.table)
library(rbenchmark)

DT = data.table(x=rep(c("a","b",NA),each=3e6), y=c(1,3,6), v=1:9)
setkey(DT,x)  

benchmark(DT["a",],
          DT[is.na(x),],
          DT[NA_character_], 
          replications=20)

            test replications elapsed relative user.self sys.self
1      DT["a", ]           20   4.763    1.238     4.000    0.567
2 DT[is.na(x), ]           20   5.399    1.403     4.537    0.794
3         DT[NA]           20   3.847    1.000     3.215    0.600 # <~~~ 
19
Arun