Подтвердить что ты не робот

Как сделать отрицательный/номенклатурный/обратный поиск в 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, и я нигде не стал.

4b9b3361

Ответ 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"]]. Кроме того, он будет работать даже тогда, когда в ключе есть несколько столбцов, которых в настоящее время нет.