Ответ 1
К счастью, 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
По мере уменьшения размера возвращаемого подмножества (например, добавления большего числа групп) разница становится очевидной. Векторные сканирование в одном столбце не так уж плохо, но на 2 или более столбцах он быстро ухудшается.
Возможно, NA должны быть присоединены к. Я, кажется, помню, что это было с этим. Здесь некоторая история связана с FR # 1043 Разрешить или запретить NA в ключах?. В нем упоминается, что NA_integer_
внутренне является отрицательным целым числом. Это вызывает сортировку radix/counting (iirc), в результате чего setkey
идет медленнее. Но это в списке, чтобы вернуться.