データテーブルの主キーに値が欠落しているすべての行を選択するにはどうすればよいですか。
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
幸い、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
の速度が低下します。しかし、それは再訪するリストにあります。
oバイナリ検索で、
NA
/NaN
sをサブセット化できるようになりました。また、joins
s/merges
sを照合することで、NA
とNaN
を実行できます。
現時点では、正しい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 # <~~~