Primer elemento de un grupo dentro de un dataframe de R

Hoy he encontrado una solución decente a un problema que venía arrastrando desde hace un tiempo en R. Tengo una tabla muy grande (decenas de millones de registros) con su id. Me interesa quedarme con el subconjunto de la tabla original en que para cada id el valor de una determinada variable es mínimo.

Un caso de uso: esa variable adicional mide la distancia de la observación a los centroides de unos clústers. El registro con el menor valor proporciona la asignación del sujeto a su grupo.

Busqué en vano solución adecuada. Con data.table es posible construir un rank por id y seleccionar después los valores en que rank == 1. Pero es muy lengo. ddply, todavía peor. Todo lentísimo.

Hoy se me ha ocurrido una solución mucho mejor que las anteriores basada en duplicated y que resumo aquí:

library(data.table)

set.seed(1234)

a <- sample(letters, 1e6, replace = T)
b <- rnorm(length(a))

dat <- data.frame(a = a, b = b)

dat <- data.table(dat, key = c("a", "b"))
res <- dat[!duplicated(dat$a),]

head(res)
# a         b
# 1: a -3.999523
# 2: b -3.794408
# 3: c -4.422542
# 4: d -4.007013
# 5: e -4.079149
# 6: f -3.860507

head(tapply(dat$b, dat$a, min))
# a         b         c         d         e         f
# -3.999523 -3.794408 -4.422542 -4.007013 -4.079149 -3.860507

Uso data.table para ordenar la tabla por las columnas de interés. Y duplicated genera un vector lógico que es FALSE en la primera aparición de un id y TRUE en las siguientes.

Comentarios:

  • Si tus datos son pequeños, casi cualquier cosa que intentes funcionará. Pero si no,…
  • A veces pierdes horas y horas porque Google te conduce a una página (en la que ninguna de las opciones resulta convincente) en lugar de a otra donde aguardaba la respuesta a mis problemas.
  • El hecho de que una solución que considerabas ingeniosa haya sido antes descrita por otro antes no hace sino recordarnos que, independientemente quién seas, para quién trabajes o dónde estés, casi todo el talento, casi todas las buenas ideas, casi todas las respuetas, están fuera, no entre esas cuatro paredes que ves ahora mismo a tu alrededor.