¿Cómo hago una búsqueda negativa/nomatch/inversa en data.table?
select (2)
¿Qué sucede si deseo seleccionar todas las filas de una tabla de datos que no contengan un valor particular en la variable clave mediante la búsqueda binaria? Por cierto, ¿cuál es la jerga correcta para lo que quiero hacer? ¿Es "nojoin"? ¿Es "selección negativa"?
DT = data.table(x=rep(c("a","b","c"),each=3), y=c(1,3,6), v=1:9)
setkey(DT,x)
Permite hacer una selección positiva para todas las filas donde x == "a" pero utilizando la búsqueda binaria
DT["a"]
Eso es hermoso pero quiero lo contrario de eso. Quiero todas las filas que no sean "a" en otras palabras, donde x! = "A"
DT[x!="a"]
Eso es un escaneo vectorial. La línea anterior funciona, pero utiliza el escaneo vectorial. Quiero usar binario. Esperaba que funcionara lo siguiente, pero por desgracia ...
DT[!"a"]
DT[-"a"]
Los dos anteriores no funcionan y tratar de jugar con nomatch no me llevó a ninguna parte.
El idioma es este:
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
Inspiración de:
- La publicación de la lista de correo Devolución Seleccione / Únase que NO coincide?
- La pregunta anterior no-une con data.tables.
- La answer Matthew Dowle a las operaciones de conjuntos de puertos de los marcos de datos de R a las tablas de datos: ¿Cómo identificar filas duplicadas?
Actualizar Nuevo en v1.8.3 es sintaxis de unión. La primera expectativa de Farrel ( !
lugar de -
) se ha implementado:
DT[-DT["a",which=TRUE,nomatch=0],...] # old idiom
DT[!"a",...] # same result, now preferred.
Consulte el elemento NEWS para obtener información más detallada y un ejemplo.
La respuesta de Andrie es genial, y es lo que probablemente usaría. Curiosamente, sin embargo, la siguiente construcción parece ser (solo un poco) más rápida, especialmente a medida que aumenta el tamaño de las tablas de datos.
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
Estaría especialmente tentado a usar esto si se pudiera hacer que DT[,x]
devuelva una tabla de datos en lugar de un vector. Luego, la construcción podría simplificarse un poco a DT[unique(DT[,x])[x!="a"]]
. Además, entonces funcionaría incluso cuando hay múltiples columnas en la clave, lo que actualmente no lo hace.