r data.table

La sintaxis de data.table para la combinación izquierda(una columna) que prefiera



(1)

¿Cómo debo empezar a pensar qué sintaxis prefiero?

Mi criterio es la eficiencia (este es el número uno) y también la legibilidad / mantenibilidad.

Esta

A <- B[A, on = .(id)] # wow such. concision

O eso

A[B, on = .(id), comment := i.comment]

O incluso (como sugiere PoGibas):

A <- merge(A, B, all.x = TRUE)

Para completar, entonces una forma más básica es usar match() :

A[, comment := B[chmatch(A[["id"]], id), comment]]

Datos de ejemplo:

library(data.table) A <- data.table(id = letters[1:10], amount = rnorm(10)^2) B <- data.table(id = c("c", "d", "e"), comment = c("big", "slow", "nice"))


Prefiero el lenguaje "update join" por eficiencia y facilidad de mantenimiento: **

DT[WHERE, v := FROM[.SD, on=, x.v]]

Es una extensión de lo que se muestra en la vignette("datatable-reference-semantics") en "Actualizar algunas filas de columnas por referencia - subasignar por referencia". Una vez que haya una viñeta disponible en las combinaciones, eso también debería ser una buena referencia.

Esto es eficiente ya que solo usa las filas seleccionadas por WHERE y modifica o agrega la columna en el lugar, en lugar de hacer una nueva tabla como la combinación izquierda más concisa FROM[DT, on=] .

Hace que mi código sea más legible ya que puedo ver fácilmente que el punto de la unión es agregar la columna v ; y no tengo que pensar en la jerga "izquierda" / "derecha" de SQL o si el número de filas se conserva después de la unión.

Es útil para el mantenimiento del código, ya que si más adelante quiero saber cómo DT obtuvo una columna llamada v , puedo buscar en mi código v := , mientras que FROM[DT, on=] oculta qué nuevas columnas se están agregando. Además, permite la condición WHERE , mientras que la unión izquierda no lo hace. Esto puede ser útil, por ejemplo, si se usa FROM para "llenar" NA en una columna existente v .

En comparación con el otro enfoque de combinación de actualización DT[FROM, on=, v := iv] , se me ocurren dos ventajas. Primero está la opción de usar la cláusula WHERE , y la segunda es la transparencia a través de las advertencias cuando hay problemas con la unión, como coincidencias duplicadas en FROM condicional en las reglas on= . Aquí hay una ilustración que extiende el ejemplo del OP:

library(data.table) A <- data.table(id = letters[1:10], amount = rnorm(10)^2) B2 <- data.table( id = c("c", "d", "e", "e"), ord = 1:4, comment = c("big", "slow", "nice", "nooice") ) # left-joiny update A[B2, on=.(id), comment := i.comment, verbose=TRUE] # Calculated ad hoc index in 0.000s elapsed (0.000s cpu) # Starting bmerge ...done in 0.000s elapsed (0.000s cpu) # Detected that j uses these columns: comment,i.comment # Assigning to 4 row subset of 10 rows # my preferred update A[, comment2 := B2[A, on=.(id), x.comment]] # Warning message: # In `[.data.table`(A, , `:=`(comment2, B2[A, on = .(id), x.comment])) : # Supplied 11 items to be assigned to 10 items of column ''comment2'' (1 unused) id amount comment comment2 1: a 0.20000990 <NA> <NA> 2: b 1.42146573 <NA> <NA> 3: c 0.73047544 big big 4: d 0.04128676 slow slow 5: e 0.82195377 nooice nice 6: f 0.39013550 <NA> nooice 7: g 0.27019768 <NA> <NA> 8: h 0.36017876 <NA> <NA> 9: i 1.81865721 <NA> <NA> 10: j 4.86711754 <NA> <NA>

En la actualización con sabor a la izquierda, obtiene silenciosamente el valor final del comment , aunque hay dos coincidencias para id == "e" ; mientras está en la otra actualización, recibe un mensaje de advertencia útil (actualizado a un error en una versión futura ). Incluso activar verbose=TRUE con el enfoque de unión izquierda no es informativo; dice que hay cuatro filas que se están actualizando, pero no dice que una fila se esté actualizando dos veces.

Encuentro que este enfoque funciona mejor cuando mis datos se organizan en un conjunto de tablas ordenadas / relacionales. Una buena referencia al respecto es el artículo de Hadley Wickham .

** En este idioma, la parte on= debe completarse con los nombres y las reglas de la columna de unión, como on=.(id) o on=.(from_date >= dt_date) . Se pueden pasar otras reglas de unión con roll= , mult= y nomatch= . Ver ?data.table para más detalles. Gracias a @RYoda por señalar este punto en los comentarios.

Aquí hay un ejemplo más complicado de Matt Dowle que explica roll= : Encuentre el tiempo para la ocurrencia más cercana de un valor particular para cada fila

Otro ejemplo relacionado: Unirse a la izquierda usando data.table