para - Ordenar una tabla de datos rápido por orden ascendente/descendente
ordenar datos en excel ascendente y descendente (2)
Tengo una tabla de datos con aproximadamente 3 millones de filas y 40 columnas. Me gustaría ordenar esta tabla por orden descendente dentro de grupos como el siguiente código simulado de SQL:
sort by ascending Year, ascending MemberID, descending Month
¿Hay una forma equivalente en data.table para hacer esto? Hasta ahora tengo que dividirlo en 2 pasos:
setkey(X, Year, MemberID)
Esto es muy rápido y toma solo unos segundos.
X <- X[,.SD[order(-Month)],by=list(Year, MemberID)]
Este paso lleva mucho más tiempo (5 minutos).
Actualización: alguien hizo un comentario para hacer X <- X[sort(Year, MemberID, -Month)]
y luego se eliminó. Este enfoque parece ser mucho más rápido:
user system elapsed
5.560 11.242 66.236
Mi enfoque: setkey () y luego ordenar (-Month)
user system elapsed
816.144 9.648 848.798
Mi pregunta es ahora: si quiero resumir por Año, MemberId y Mes después de la ordenación (Year, MemberID, Month), ¿data.table reconoce el orden de clasificación?
Actualización 2: a la respuesta a Matthew Dowle:
Después de configurar keykey con Year, MemberID y Month, todavía tengo varios registros por grupo. Lo que me gustaría es resumir para cada uno de los grupos. Lo que quise decir fue: si uso X [orden (Año, MemberID, Mes)], ¿la suma utiliza la función de búsqueda binaria de data.table:
monthly.X <- X[, lapply(.SD[], sum), by = list(Year, MemberID, Month)]
Actualización 3: Mateo D propuso varios enfoques. El tiempo de ejecución para el primer enfoque es más rápido que el enfoque de orden ():
user system elapsed
7.910 7.750 53.916
Matthew: lo que me sorprendió fue que convertir el signo del mes lleva la mayor parte del tiempo. Sin él, setkey está ardiendo rápidamente.
Actualización del 5 de junio de 2014:
La versión de desarrollo actual de data.table v1.9.3 tiene dos nuevas funciones implementadas, a saber: setorder
y setorderv
, que hace exactamente lo que usted necesita. Estas funciones reordenan el data.table
por referencia con la opción de elegir orden ascendente o descendente en cada columna para ordenar. Echa un vistazo a ?setorder
para más información.
Además, DT[order(.)]
También está optimizado de manera predeterminada para usar el orden rápido interno de data.table
lugar del base:::order
. Esto, a diferencia del setorder
, hará una copia completa de los datos, y por lo tanto es menos eficiente en memoria, pero seguirá siendo órdenes de magnitud más rápido que operando usando el orden de la base.
Puntos de referencia:
Aquí hay una ilustración de las diferencias de velocidad usando setorder
, el orden rápido interno de data.table y con base:::order
:
require(data.table) ## 1.9.3
set.seed(1L)
DT <- data.table(Year = sample(1950:2000, 3e6, TRUE),
memberID = sample(paste0("V", 1:1e4), 3e6, TRUE),
month = sample(12, 3e6, TRUE))
## using base:::order
system.time(ans1 <- DT[base:::order(Year, memberID, -month)])
# user system elapsed
# 76.909 0.262 81.266
## optimised to use data.table''s fast order
system.time(ans2 <- DT[order(Year, memberID, -month)])
# user system elapsed
# 0.985 0.030 1.027
## reorders by reference
system.time(setorder(DT, Year, memberID, -month))
# user system elapsed
# 0.585 0.013 0.600
## or alternatively
## setorderv(DT, c("Year", "memberID", "month"), c(1,1,-1))
## are they equal?
identical(ans2, DT) # [1] TRUE
identical(ans1, ans2) # [1] TRUE
En estos datos, los puntos de referencia indican que el orden de data.table es aproximadamente ~ 79x más rápido que el base:::order
y el base:::order
setorder
es ~ 135x más rápido que el base:::order
aquí.
data.table
siempre ordena / ordena en C-locale. Si debe solicitar en otra configuración regional, solo entonces debe recurrir al uso de DT[base:::order(.)]
.
Todas estas nuevas optimizaciones y funciones juntas constituyen FR # 2405 . También se ha agregado soporte para bit64 :: integer64 .
NOTA: Consulte el historial / revisiones para obtener respuestas y actualizaciones anteriores.
El comentario fue mío, así que voy a publicar la respuesta. Lo quité porque no pude probar si era equivalente a lo que ya tenías. Me alegra saber que es más rápido.
X <- X[order(Year, MemberID, -Month)]
El resumen no debe depender del orden de sus filas.