Quiero ordenar un data.frame por varias columnas. Por ejemplo, con el data.frame a continuación, me gustaría ordenar por columna z
(descendente) y luego por columna b
(ascendente):
dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"),
levels = c("Low", "Med", "Hi"), ordered = TRUE),
x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
z = c(1, 1, 1, 2))
dd
b x y z
1 Hi A 8 1
2 Med D 3 1
3 Hi A 9 1
4 Low C 9 2
with
. IntenteM <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b")))
crear una matrizM
, luego useM[order(M[,"a"],-M[,"b"]),]
para ordenarla en dos columnas.dd[ order(-dd[,4], dd[,1]), ]
pero no se puede usarwith
para subconjuntos basados en nombres.xtfrm
, por ejemplodd[ order(-xtfrm(dd[,4]), dd[,1]), ]
.Tus opciones
order
desdebase
arrange
desdedplyr
setorder
ysetorderv
dedata.table
arrange
desdeplyr
sort
desdetaRifx
orderBy
desdedoBy
sortData
desdeDeducer
La mayoría de las veces debe usar las soluciones
dplyr
odata.table
, a menos que sea importante no tener dependencias, en cuyo caso usebase::order
.Recientemente agregué sort.data.frame a un paquete CRAN, haciéndolo compatible con la clase como se explica aquí: ¿La mejor manera de crear consistencia genérica / de método para sort.data.frame?
Por lo tanto, dado el data.frame dd, puede ordenar de la siguiente manera:
Si usted es uno de los autores originales de esta función, contácteme. La discusión sobre dominio público está aquí: http://chat.stackoverflow.com/transcript/message/1094290#1094290
También puede usar la
arrange()
funciónplyr
como señaló Hadley en el hilo anterior:Puntos de referencia: tenga en cuenta que cargué cada paquete en una nueva sesión de R ya que hubo muchos conflictos. En particular, al cargar el paquete doBy se
sort
devuelve "Los siguientes objetos se enmascaran desde 'x (posición 17)': b, x, y, z", y al cargar el paquete Deducer se sobrescribesort.data.frame
de Kevin Wright o del paquete taRifx.Tiempos medianos:
dd[with(dd, order(-z, b)), ]
778dd[order(-dd$z, dd$b),]
788Tiempo medio: 1,567
Tiempo medio: 862
Tiempo medio: 1,694
Tenga en cuenta que doBy tarda bastante tiempo en cargar el paquete.
No se pudo hacer que la carga del deductor. Necesita consola JGR.
No parece ser compatible con microbenchmark debido a la conexión / desconexión.
(las líneas se extienden desde el cuartil inferior al cuartil superior, el punto es la mediana)
Teniendo en cuenta estos resultados y un peso de velocidad frente a la simplicidad, que tendría que dar el visto bueno a
arrange
laplyr
paquete . Tiene una sintaxis simple y, sin embargo, es casi tan rápida como los comandos base R con sus complicadas maquinaciones. Típicamente brillante trabajo de Hadley Wickham. Mi única queja es que rompe la nomenclatura R estándar por la que se llama a los objetos de clasificaciónsort(object)
, pero entiendo por qué Hadley lo hizo de esa manera debido a los problemas discutidos en la pregunta vinculada anteriormente.fuente
taRifx::autoplot.microbenchmark
.b
se ordena en la muestra. El valor predeterminado es ordenar por ascendente, por lo que simplemente no lo ajustadesc
. Ascendente en ambos:arrange(dd,z,b)
. Descendente en ambos:arrange(dd,desc(z),desc(b))
.?arrange
: "# NOTA: las funciones de plyr NO conservan row.names". Esto hace que la excelentearrange()
función sea subóptima si se quiere mantenerrow.names
.La respuesta de Dirk es genial. También destaca una diferencia clave en la sintaxis utilizada para la indexación
data.frame
s ydata.table
s:La diferencia entre las dos llamadas es pequeña, pero puede tener consecuencias importantes. Especialmente si escribe código de producción y / o le preocupa la corrección en su investigación, es mejor evitar la repetición innecesaria de nombres de variables.
data.table
te ayuda a hacer esto.Aquí hay un ejemplo de cómo la repetición de nombres de variables puede meterte en problemas:
Cambiemos el contexto de la respuesta de Dirk, y digamos que esto es parte de un proyecto más grande donde hay muchos nombres de objetos y son largos y significativos; en lugar de
dd
que se llamaquarterlyreport
. Se vuelve :Está bien. Nada de malo con eso. Luego, su jefe le pide que incluya el informe del último trimestre en el informe. Revisas tu código, agregas un objeto
lastquarterlyreport
en varios lugares y de alguna manera (¿cómo demonios?) Terminas con esto:Eso no es lo que quiso decir, pero no lo detectó porque lo hizo rápido y está ubicado en una página de código similar. El código no se cae (sin advertencia ni error) porque R cree que es lo que quiso decir. Esperarías que quien lea tu informe lo vea, pero tal vez no. Si trabajas mucho con lenguajes de programación, esta situación puede ser muy familiar. Fue un "error tipográfico" que dirás. Arreglaré el "error tipográfico" que le dirás a tu jefe.
En
data.table
nosotros estamos preocupados por pequeños detalles como este. Así que hemos hecho algo simple para evitar escribir nombres de variables dos veces. Algo muy simple.i
se evalúa dentro del marco dedd
ya, automáticamente. No necesitaswith()
nada.En vez de
es solo
Y en lugar de
es solo
Es una diferencia muy pequeña, pero podría salvarte el cuello algún día. Al sopesar las diferentes respuestas a esta pregunta, considere contar las repeticiones de nombres de variables como uno de sus criterios para decidir. Algunas respuestas tienen bastantes repeticiones, otras no.
fuente
subset()
solo para evitar tener que referirme repetidamente al mismo objeto dentro de una sola llamada.setorder
función aquí, ya que este hilo es donde enviamos todos losorder
tipos duplicados.Aquí hay muchas respuestas excelentes, pero dplyr ofrece la única sintaxis que puedo recordar rápida y fácilmente (y ahora uso muy a menudo):
Para el problema del OP:
fuente
dd[order(-z, b)]
bastante fácil de usar y recordar.data.table
es una gran contribuciónR
en muchas otras formas. Supongo que para mí, podría ser que tener un conjunto de paréntesis menos (o un tipo de paréntesis menos) en este caso reduce la carga cognitiva en una cantidad apenas perceptible.arrange()
es completamente declarativo,dd[order(-z, b)]
no lo es.El paquete R
data.table
proporciona un ordenamiento rápido y eficiente de la memoria de data.tables con una sintaxis directa (una parte de la cual Matt ha resaltado bastante bien en su respuesta ). Ha habido muchas mejoras y también una nueva funciónsetorder()
desde entonces. Desdev1.9.5+
,setorder()
también funciona con data.frames .Primero, crearemos un conjunto de datos lo suficientemente grande y compararemos los diferentes métodos mencionados en otras respuestas y luego enumeraremos las características de data.table .
Datos:
Puntos de referencia:
Los tiempos informados se ejecutan
system.time(...)
en estas funciones que se muestran a continuación. Los tiempos se tabulan a continuación (en el orden de más lento a más rápido).data.table
LaDT[order(...)]
sintaxis fue ~ 10 veces más rápida que la más rápida de otros métodos (dplyr
), mientras consumía la misma cantidad de memoria quedplyr
.data.table
'ssetorder()
fue ~ 14 veces más rápido que el más rápido de otros métodos (dplyr
), mientras que solo tenía 0.4GB de memoria extra .dat
ahora está en el orden que requerimos (ya que se actualiza por referencia).Características de data.table:
Velocidad:
El pedido de data.table es extremadamente rápido porque implementa el pedido de radix .
La sintaxis
DT[order(...)]
está optimizada internamente para usar también el ordenamiento rápido de data.table . Puede seguir usando la sintaxis base R familiar pero acelerar el proceso (y usar menos memoria).Memoria:
La mayoría de las veces, no requerimos el data.frame o data.table original después de reordenar. Es decir, generalmente asignamos el resultado al mismo objeto, por ejemplo:
El problema es que esto requiere al menos dos veces (2x) la memoria del objeto original. Para ser eficiente en la memoria , data.table , por lo tanto, también proporciona una función
setorder()
.setorder()
reordena data.tablesby reference
( en el lugar ), sin hacer copias adicionales. Solo usa memoria adicional igual al tamaño de una columna.Otras características:
Es compatible
integer
,logical
,numeric
,character
e incluso losbit64::integer64
tipos.En la base R, no podemos usar
-
un vector de caracteres para ordenar por esa columna en orden decreciente. En cambio tenemos que usar-xtfrm(.)
.Sin embargo, en data.table , podemos hacer, por ejemplo,
dat[order(-x)]
osetorder(dat, -x)
.fuente
Con esta función (muy útil) de Kevin Wright , publicada en la sección de consejos de R wiki, esto se logra fácilmente.
fuente
o puedes usar el paquete doBy
fuente
Suponga que tiene un
data.frame
A
y desea ordenarlo usando una columna llamadax
orden descendente. Llamar a los ordenadosdata.frame
newdata
Si desea un orden ascendente, reemplácelo
"-"
con nada. Puedes tener algo comodonde
x
yz
son algunas columnas endata.frame
A
. Esto significa ordenardata.frame
A
porx
descendente,y
ascendente yz
descendente.fuente
Si SQL es algo natural para usted, el
sqldf
paquete se encarga de loORDER BY
que Codd pretendía.fuente
Alternativamente, usando el paquete Deducer
fuente
En respuesta a un comentario agregado en el OP sobre cómo ordenar mediante programación:
Usando
dplyr
ydata.table
dplyr
Simplemente use
arrange_
, que es la versión de Evaluación estándar paraarrange
.Más información aquí: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html
Es mejor usar la fórmula, ya que también captura el entorno para evaluar una expresión en
tabla de datos
fuente
Aprendí
order
con el siguiente ejemplo que luego me confundió durante mucho tiempo:La única razón por la que funciona este ejemplo es porque
order
está ordenando porvector Age
, no por la columna nombradaAge
endata frame data
.Para ver esto, cree un marco de datos idéntico
read.table
con nombres de columna ligeramente diferentes y sin utilizar ninguno de los vectores anteriores:La estructura de línea anterior
order
ya no funciona porque no hay un vector llamadoage
:La siguiente línea funciona porque
order
las clases en la columnaage
demy.data
.Pensé que valía la pena publicarlo dado lo confundido que estaba con este ejemplo durante tanto tiempo. Si esta publicación no se considera apropiada para el hilo, puedo eliminarla.
EDITAR: 13 de mayo de 2014
A continuación se muestra una forma generalizada de ordenar un marco de datos por cada columna sin especificar los nombres de las columnas. El siguiente código muestra cómo ordenar de izquierda a derecha o de derecha a izquierda. Esto funciona si cada columna es numérica. No lo he intentado con una columna de caracteres añadida.
Encontré el
do.call
código hace un mes o dos en una publicación anterior en un sitio diferente, pero solo después de una búsqueda extensa y difícil. No estoy seguro de poder reubicar esa publicación ahora. El presente hilo es el primer golpe para pedir unadata.frame
enR
. Entonces, pensé que mi versión ampliada de esedo.call
código original podría ser útil.fuente
require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]
esto funciona porque los nombres de columna están disponibles dentro de los corchetes [].data.frame
s para usarwith
o$
.do.call
esto hace un trabajo corto de ordenar un marco de datos de varias columnas. Simplementedo.call(sort, mydf.obj)
y se tendrá una hermosa especie de cascada.La respuesta de Dirk es buena, pero si necesita que el ordenamiento persista, querrá volver a aplicar el ordenamiento en el nombre de ese marco de datos. Usando el código de ejemplo:
fuente
El arreglo () en dplyer es mi opción favorita. Use el operador de tubería y pase del aspecto menos importante al más importante
fuente
Solo en aras de la exhaustividad, ya que no se ha dicho mucho sobre la clasificación por números de columna ... Seguramente se puede argumentar que a menudo no es deseable (porque el orden de las columnas podría cambiar, allanando el camino a los errores), pero En algunas situaciones específicas (cuando, por ejemplo, necesita un trabajo rápido y no existe el riesgo de que las columnas cambien el orden), podría ser lo más sensato, especialmente cuando se trata de grandes cantidades de columnas.
En ese caso,
do.call()
viene al rescate:fuente
En aras de la exhaustividad: también puede utilizar la
sortByCol()
función delBBmisc
paquete:Comparación de rendimiento:
fuente
data.frame
Al igual que los clasificadores de tarjetas mecánicas de antaño, primero ordene por la clave menos significativa, luego la siguiente más significativa, etc. No se requiere biblioteca, funciona con cualquier número de teclas y cualquier combinación de teclas ascendentes y descendentes.
Ahora estamos listos para hacer la clave más significativa. El tipo es estable, y cualquier vínculo en la clave más significativa ya se ha resuelto.
Puede que este no sea el más rápido, pero sin duda es simple y confiable.
fuente
Otra alternativa, usando el
rgr
paquete:fuente
Estaba luchando con las soluciones anteriores cuando quería automatizar mi proceso de pedido para n columnas, cuyos nombres de columna podían ser diferentes cada vez. Encontré una función súper útil del
psych
paquete para hacer esto de una manera directa:donde
columnIndices
están los índices de una o más columnas, en el orden en que desea ordenarlas. Más información aquí:Función dfOrder del paquete 'psych'
fuente