24

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

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
4

2 に答える 2

22

幸いなことに、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速度が低下します。しかし、それは再訪するリストにあります。

于 2012-09-28T20:01:03.087 に答える
20

これはv1.8.11で実装されるようになりました。ニュースから:

oバイナリ検索で、NA/ sをサブセット化できるようになり、 s/ sを照合しNaNて実行することもできます。joinsmergesNANaN

ただし、現時点では正しいNA(など)を明示的NA_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 # <~~~ 
于 2013-12-15T01:06:41.370 に答える