Rolling join en data.table con claves duplicadas

Estoy tratando de entender rolling joins data.table en data.table . Los datos para reproducir esto se dan al final.

Dada una tabla de datos de transacciones en un aeropuerto, en un momento dado:

 > dt t_id airport thisTime 1: 1 a 5.1 2: 3 a 5.1 3: 2 a 6.2 

(nota t_ids 1 y 3 tienen el mismo aeropuerto y hora)

y una tabla de búsqueda de vuelos que salen de los aeropuertos:

 > dt_lookup f_id airport thisTime 1: 1 a 6 2: 2 a 6 3: 1 b 7 4: 1 c 8 5: 2 d 7 6: 1 d 9 7: 2 e 8 > tables() NAME NROW NCOL MB COLS KEY [1,] dt 3 3 1 t_id,airport,thisTime airport,thisTime [2,] dt_lookup 7 3 1 f_id,airport,thisTime airport,thisTime 

Me gustaría relacionar todas las transacciones con todos los próximos vuelos posibles que salgan de ese aeropuerto, para dar:

  t_id airport thisTime f_id 1 a 6 1 1 a 6 2 3 a 6 1 3 a 6 2 

Entonces pensé que esto funcionaría:

 > dt[dt_lookup, nomatch=0,roll=Inf] t_id airport thisTime f_id 1: 3 a 6 1 2: 3 a 6 2 

Pero no ha devuelto las transacciones t_id == 1 .

De la documentación dice:

Por lo general, no debe haber duplicados en la clave de x, …

Sin embargo, tengo duplicados en mi ‘x key’ (es decir, airport & thisTime ), y no puedo ver / entender qué significa que t_id = 1 se elimina de la salida.

¿Alguien puede arrojar algo de luz sobre por qué t_id = 1 no se devuelve, y cómo puedo obtener la unión para trabajar cuando tengo duplicados?

Datos

 library(data.table) dt <- data.table(t_id = seq(1:3), airport = c("a","a","a"), thisTime = c(5.1,6.2, 5.1), key=c( "airport","thisTime")) dt_lookup <- data.table(f_id = c(rep(1,4),rep(2,3)), airport = c("a","b","c","d", "a","d","e"), thisTime = c(6,7,8,9, 6,7,8), key=c("airport","thisTime")) 

La razón por la que t_id = 1 no aparece en el resultado es porque una combinación continua toma la fila donde ocurre la combinación de teclas por última vez. De la documentación (énfasis mío):

Se aplica a la última columna de unión, generalmente una fecha, pero puede ser cualquier variable ordenada, irregular e incluyendo espacios. Si roll = TRUE y la fila i coincide con todas menos la última columna x join, y su valor en la última columna i join cae en un espacio (incluso después de la última observación en x para ese grupo), entonces el valor predominante en x es rodó hacia adelante. Esta operación es particularmente rápida usando una búsqueda binaria modificada. La operación también se conoce como última observación trasladada (LOCF).

Consideremos conjuntos de datos algo más grandes:

 > DT t_id airport thisTime 1: 1 a 5.1 2: 4 a 5.1 3: 3 a 5.1 4: 2 d 6.2 5: 5 d 6.2 > DT_LU f_id airport thisTime 1: 1 a 6 2: 2 a 6 3: 2 a 8 4: 1 b 7 5: 1 c 8 6: 2 d 7 7: 1 d 9 

Cuando realizas una unión continua al igual que en tu pregunta:

 DT[DT_LU, nomatch=0, roll=Inf] 

usted obtiene:

  t_id airport thisTime f_id 1: 3 a 6 1 2: 3 a 6 2 3: 3 a 8 2 4: 5 d 7 2 5: 5 d 9 1 

Como puede ver, de la combinación de teclas a, 5.1 d, 6.2 la última fila se usa para la tabla de datos unida. Debido a que usa Inf como valor en rollo, todos los valores futuros se incorporan en la tabla de datos resultante. Cuando usas:

 DT[DT_LU, nomatch=0, roll=1] 

ves que solo el primer valor en el futuro está incluido:

  t_id airport thisTime f_id 1: 3 a 6 1 2: 3 a 6 2 3: 5 d 7 2 

Si quiere los f_id ‘s para todas las combinaciones de airport y thisTime donde DT$thisTime es menor que DT_LU$thisTime , puede lograrlo creando una nueva variable (o reemplazando el thisTime existente) por medio de la función de ceiling . Un ejemplo donde creo una nueva variable thisTime2 y luego hago una unión normal con DT_LU :

 DT[, thisTime2 := ceiling(thisTime)] setkey(DT, airport, thisTime2)[DT_LU, nomatch=0] 

lo que da:

  t_id airport thisTime thisTime2 f_id 1: 1 a 5.1 6 1 2: 4 a 5.1 6 1 3: 3 a 5.1 6 1 4: 1 a 5.1 6 2 5: 4 a 5.1 6 2 6: 3 a 5.1 6 2 7: 2 d 6.2 7 2 8: 5 d 6.2 7 2 

Aplicado a la información que brindó:

 > dt[, thisTime2 := ceiling(thisTime)] > setkey(dt, airport, thisTime2)[dt_lookup, nomatch=0] t_id airport thisTime thisTime2 f_id 1: 1 a 5.1 6 1 2: 3 a 5.1 6 1 3: 1 a 5.1 6 2 4: 3 a 5.1 6 2 

Cuando desee incluir todos los valores futuros en lugar de solo el primero, necesita un enfoque algo diferente para el cual necesitará la funcionalidad i.col (que aún no está documentada):

1 : Primero configure la clave solo para las columnas del airport :

 setkey(DT, airport) setkey(DT_LU, airport) 

2 : utilice la funcionalidad i.col (que aún no está documentada) en j para obtener lo que desea de la siguiente manera:

 DT1 < - DT_LU[DT, .(tid = i.t_id, tTime = i.thisTime, fTime = thisTime[i.thisTime < thisTime], fid = f_id[i.thisTime < thisTime]), by=.EACHI] 

esto te da:

 > DT1 airport tid tTime fTime fid 1: a 1 5.1 6 1 2: a 1 5.1 6 2 3: a 1 5.1 8 2 4: a 4 5.1 6 1 5: a 4 5.1 6 2 6: a 4 5.1 8 2 7: a 3 5.1 6 1 8: a 3 5.1 6 2 9: a 3 5.1 8 2 10: d 2 6.2 7 2 11: d 2 6.2 9 1 12: d 5 6.2 7 2 13: d 5 6.2 9 1 

Algunas explicaciones: en el caso de que se una a dos tablas de datos donde se usan los mismos nombres de columna, puede consultar las columnas de la tabla de datos en i precediendo los nombres de las columnas con i. . Ahora es posible comparar thisTime de DT con thisTime de DT_LU . Con by = .EACHI usted asegura que todas las combinaciones para con las suspensiones de condición se incluyen en la tabla de datos resultante.

Alternativamente, puede lograr lo mismo con:

 DT2 < - DT_LU[DT, .(airport=i.airport, tid=i.t_id, tTime=i.thisTime, fTime=thisTime[i.thisTime < thisTime], fid=f_id[i.thisTime < thisTime]), allow.cartesian=TRUE] 

que da el mismo resultado:

 > identical(DT1, DT2) [1] TRUE 

Cuando solo desee incluir valores futuros dentro de un límite determinado, puede usar:

 DT1 < - DT_LU[DT, { idx = i.thisTime < thisTime & thisTime - i.thisTime < 2 .(tid = i.t_id, tTime = i.thisTime, fTime = thisTime[idx], fid = f_id[idx]) }, by=.EACHI] 

lo que da:

 > DT1 airport tid tTime fTime fid 1: a 1 5.1 6 1 2: a 1 5.1 6 2 3: a 4 5.1 6 1 4: a 4 5.1 6 2 5: a 3 5.1 6 1 6: a 3 5.1 6 2 7: d 2 6.2 7 2 8: d 5 6.2 7 2 

Cuando compara eso con el resultado anterior, ve que ahora se han eliminado las filas 3, 6, 9, 10 y 12.


Datos:

 DT < - data.table(t_id = c(1,4,2,3,5), airport = c("a","a","d","a","d"), thisTime = c(5.1, 5.1, 6.2, 5.1, 6.2), key=c("airport","thisTime")) DT_LU <- data.table(f_id = c(rep(1,4),rep(2,3)), airport = c("a","b","c","d","a","d","e"), thisTime = c(6,7,8,9,6,7,8), key=c("airport","thisTime"))