Как сделать отрицательный/номенклатурный/обратный поиск в data.table?
Что произойдет, если я хочу выбрать все строки в таблице data.table, которые не содержат конкретного значения в ключевой переменной, используя двоичный поиск? Кстати, какой правильный жаргон для того, что я хочу сделать? Это "nojoin"? Это "отрицательный выбор"?
DT = data.table(x=rep(c("a","b","c"),each=3), y=c(1,3,6), v=1:9)
setkey(DT,x)
Позволяет сделать положительный выбор для всех строк, где x == "a", но используя двоичный поиск
DT["a"]
Это красиво, но я хочу, чтобы это было противоположно. Я хочу, чтобы все строки не были "а", другими словами, где x!= "A"
DT[x!="a"]
Это векторное сканирование. Вышеприведенная линия работает, но использует векторное сканирование. Я хочу использовать двоичный файл. Я ожидал, что следующее будет работать, но, увы...
DT[!"a"]
DT[-"a"]
Вышеуказанные два не работают и пытаются сыграть с nomatch, и я нигде не стал.
Ответы
Ответ 1
Идиома такова:
DT[-DT["a", which=TRUE]]
x y v
1: b 1 4
2: b 3 5
3: b 6 6
4: c 1 7
5: c 3 8
6: c 6 9
Вдохновение от:
Обновление. Новое в v1.8.3 не является синтаксисом соединения. Было реализовано первое ожидание Фаррела (!
, а не -
):
DT[-DT["a",which=TRUE,nomatch=0],...] # old idiom
DT[!"a",...] # same result, now preferred.
Более подробную информацию и пример см. в NEWS.
Ответ 2
Андри отвечает, и это то, что я бы использовал. Интересно, однако, что следующая конструкция кажется (чуть-чуть) быстрее, особенно по мере увеличения размера data.tables.
DT[J(x = unique(DT)[x!="a"][,x])]
##-------------------------------- Timings -----------------------------------##
library(data.table)
library(rbenchmark)
DT = data.table(x=rep(c("a","b","c"),each=45e5), y=c(1,3,6), v=1:9, key="x")
Josh <- function() DT[J(x = unique(DT)[x!="a"][,x])]
Andrie <- function() DT[-DT["a", which=TRUE]]
## Compare results
identical(Josh(), setkey(Andrie(), "x"))
# [1] TRUE
## Compare timings
benchmark(replications = 10, order="relative", Josh=Josh(), Andrie=Andrie())
test replications elapsed relative user.self sys.self user.child sys.child
1 Josh 10 17.50 1.000 14.78 3.6 NA NA
2 Andrie 10 18.75 1.071 16.52 3.2 NA NA
Мне особенно хотелось бы использовать это, если DT[,x]
можно было бы сделать, чтобы вернуть data.table, а не вектор. Затем конструкцию можно немного упростить до DT[unique(DT[,x])[x!="a"]]
. Кроме того, он будет работать даже тогда, когда в ключе есть несколько столбцов, которых в настоящее время нет.