Subcontar datos.tabla por segunda columna solo de una clave de 2 columnas, utilizando búsqueda binaria, no exploración vectorial

Recientemente descubrí la búsqueda binaria en data.table . Si la tabla está ordenada en varias teclas, ¿es posible buscar solo en la segunda tecla?

 DT = data.table(x=sample(letters,1e7,T),y=sample(1:25,1e7,T),rnorm(1e7)) setkey(DT,x,y) #R> DT[J('x')] # xy V3 # 1: x 1 0.89109 # 2: x 1 -2.01457 # --- #384922: x 25 0.09676 #384923: x 25 0.25168 #R> DT[J('x',3)] # xy V3 # 1: x 3 -0.88165 # 2: x 3 1.51028 # --- #15383: x 3 -1.62218 #15384: x 3 -0.63601 

EDITAR: gracias a @Arun

 R> system.time(DT[J(unique(x), 25)]) user system elapsed 0.220 0.068 0.288 R> system.time(DT[y==25]) user system elapsed 0.268 0.092 0.359 

Sí, puede pasar todos los valores al primer valor y subconjunto de clave con el valor específico para la segunda clave.

 DT[J(unique(x), 25), nomatch=0] 

Si necesita subconjunto por más de un valor en la segunda clave (por ejemplo, el equivalente de DT[y %in% 25:24] ), una solución más general es usar CJ

 DT[CJ(unique(x), 25:24), nomatch=0] 

Tenga en cuenta que CJ clasifica por defecto las columnas y establece la clave para todas las columnas, lo que significa que el resultado también será ordenado. Si eso no es deseable, debe usar sorted=FALSE

 DT[CJ(unique(x), 25:24, sorted=FALSE), nomatch=0] 

También hay una solicitud de funciones para agregar claves secundarias a data.table en el futuro. Creo que el plan es agregar una nueva función set2key .

FR # 1007 Construir en claves secundarias

También hay merge , que tiene un método para data.table . Construye la clave secundaria dentro para ti, por lo que debe ser más rápido que la fusión base. Ver ?merge.data.table .

Basado en este hilo de correo electrónico , escribí las siguientes funciones:

 create_index = function(dt, ..., verbose = getOption("datatable.verbose")) { cols = data.table:::getdots() res = dt[, cols, with=FALSE] res[, i:=1:nrow(dt)] setkeyv(res, cols, verbose = verbose) } JI = function(index, ...) { index[J(...),i]$i } 

Aquí están los resultados en mi sistema con un DT más grande (1e8 filas):

 > system.time(DT[J("c")]) user system elapsed 0.168 0.136 0.306 > system.time(DT[J(unique(x), 25)]) user system elapsed 2.472 1.508 3.980 > system.time(DT[y==25]) user system elapsed 4.532 2.149 6.674 > system.time(IDX_y <- create_index(DT, y)) user system elapsed 3.076 2.428 5.503 > system.time(DT[JI(IDX_y, 25)]) user system elapsed 0.512 0.320 0.831 

Si usa el índice varias veces, lo vale.