Cómo ordenar un marco de datos por varias columnas

1317

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
Christopher DuBois
fuente

Respuestas:

1626

Puede usar la order()función directamente sin recurrir a herramientas adicionales: consulte esta respuesta más simple que utiliza un truco desde la parte superior del example(order)código:

R> dd[with(dd, order(-z, b)), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

Edite más de 2 años después: solo se le preguntó cómo hacerlo por índice de columna. La respuesta es simplemente pasar las columnas de clasificación deseadas a la order()función:

R> dd[order(-dd[,4], dd[,1]), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1
R> 

en lugar de usar el nombre de la columna (y with()para un acceso más fácil / más directo).

Dirk Eddelbuettel
fuente
@Dirk Eddelbuettel ¿existe un método similarmente simple para las matrices?
Jota
14
Debería funcionar de la misma manera, pero no se puede usar with. Intente M <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b")))crear una matriz M, luego use M[order(M[,"a"],-M[,"b"]),]para ordenarla en dos columnas.
Dirk Eddelbuettel
44
Muy fácil: dd[ order(-dd[,4], dd[,1]), ]pero no se puede usar withpara subconjuntos basados ​​en nombres.
Dirk Eddelbuettel
18
Tengo el error "argumento no válido para operador unario" al ejecutar el segundo ejemplo.
Nailgun
21
El error "argumento no válido para operador unario" se produce cuando usa menos con una columna de caracteres. Resuélvala envolviendo la columna xtfrm, por ejemplo dd[ order(-xtfrm(dd[,4]), dd[,1]), ].
Richie Cotton
477

Tus opciones

  • order desde base
  • arrange desde dplyr
  • setordery setordervdedata.table
  • arrange desde plyr
  • sort desde taRifx
  • orderBy desde doBy
  • sortData desde Deducer

La mayoría de las veces debe usar las soluciones dplyro data.table, a menos que sea importante no tener dependencias, en cuyo caso use base::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:

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))
library(taRifx)
sort(dd, f= ~ -z + b )

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ón plyrcomo señaló Hadley en el hilo anterior:

library(plyr)
arrange(dd,desc(z),b)

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 sortdevuelve "Los siguientes objetos se enmascaran desde 'x (posición 17)': b, x, y, z", y al cargar el paquete Deducer se sobrescribe sort.data.framede Kevin Wright o del paquete taRifx.

#Load each time
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))
library(microbenchmark)

# Reload R between benchmarks
microbenchmark(dd[with(dd, order(-z, b)), ] ,
    dd[order(-dd$z, dd$b),],
    times=1000
)

Tiempos medianos:

dd[with(dd, order(-z, b)), ] 778

dd[order(-dd$z, dd$b),] 788

library(taRifx)
microbenchmark(sort(dd, f= ~-z+b ),times=1000)

Tiempo medio: 1,567

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=1000)

Tiempo medio: 862

library(doBy)
microbenchmark(orderBy(~-z+b, data=dd),times=1000)

Tiempo medio: 1,694

Tenga en cuenta que doBy tarda bastante tiempo en cargar el paquete.

library(Deducer)
microbenchmark(sortData(dd,c("z","b"),increasing= c(FALSE,TRUE)),times=1000)

No se pudo hacer que la carga del deductor. Necesita consola JGR.

esort <- function(x, sortvar, ...) {
attach(x)
x <- x[with(x,order(sortvar,...)),]
return(x)
detach(x)
}

microbenchmark(esort(dd, -z, b),times=1000)

No parece ser compatible con microbenchmark debido a la conexión / desconexión.


m <- microbenchmark(
  arrange(dd,desc(z),b),
  sort(dd, f= ~-z+b ),
  dd[with(dd, order(-z, b)), ] ,
  dd[order(-dd$z, dd$b),],
  times=1000
  )

uq <- function(x) { fivenum(x)[4]}  
lq <- function(x) { fivenum(x)[2]}

y_min <- 0 # min(by(m$time,m$expr,lq))
y_max <- max(by(m$time,m$expr,uq)) * 1.05

p <- ggplot(m,aes(x=expr,y=time)) + coord_cartesian(ylim = c( y_min , y_max )) 
p + stat_summary(fun.y=median,fun.ymin = lq, fun.ymax = uq, aes(fill=expr))

trama de microbenchmark

(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 arrangela plyrpaquete . 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ón sort(object), pero entiendo por qué Hadley lo hizo de esa manera debido a los problemas discutidos en la pregunta vinculada anteriormente.

Ari B. Friedman
fuente
3
La función de microbenchmark ggplot2 anterior ahora está disponible como taRifx::autoplot.microbenchmark.
Ari B. Friedman
@ AriB.Friedman ¿Cuáles son los intervalos del eje y / cuál es la escala?
naught101
@ naught101 El eje y comienza en 0. La escala debe ser de microsegundos.
Ari B. Friedman
2
@AME mira cómo bse ordena en la muestra. El valor predeterminado es ordenar por ascendente, por lo que simplemente no lo ajusta desc. Ascendente en ambos: arrange(dd,z,b). Descendente en ambos: arrange(dd,desc(z),desc(b)).
Ari B. Friedman
2
Según ?arrange: "# NOTA: las funciones de plyr NO conservan row.names". Esto hace que la excelente arrange()función sea subóptima si se quiere mantener row.names.
landroni
149

La respuesta de Dirk es genial. También destaca una diferencia clave en la sintaxis utilizada para la indexación data.frames y data.tables:

## The data.frame way
dd[with(dd, order(-z, b)), ]

## The data.table way: (7 fewer characters, but that's not the important bit)
dd[order(-z, b)]

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 ddque se llama quarterlyreport. Se vuelve :

quarterlyreport[with(quarterlyreport,order(-z,b)),]

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 lastquarterlyreporten varios lugares y de alguna manera (¿cómo demonios?) Terminas con esto:

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]

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.tablenosotros 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. ise evalúa dentro del marco de ddya, automáticamente. No necesitas with()nada.

En vez de

dd[with(dd, order(-z, b)), ]

es solo

dd[order(-z, b)]

Y en lugar de

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]

es solo

quarterlyreport[order(-z,b)]

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.

Matt Dowle
fuente
99
+1 Este es un gran punto, y llega a un detalle de la sintaxis de R que a menudo me ha irritado. A veces uso subset()solo para evitar tener que referirme repetidamente al mismo objeto dentro de una sola llamada.
Josh O'Brien
2
@ naught101 ¿Data.table FAQ 1.9 responde eso?
Matt Dowle el
55
Supongo que también podría agregar la nueva setorderfunción aquí, ya que este hilo es donde enviamos todos los ordertipos duplicados.
David Arenburg
125

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):

library(dplyr)
# sort mtcars by mpg, ascending... use desc(mpg) for descending
arrange(mtcars, mpg)
# sort mtcars first by mpg, then by cyl, then by wt)
arrange(mtcars , mpg, cyl, wt)

Para el problema del OP:

arrange(dd, desc(z),  b)

    b x y z
1 Low C 9 2
2 Med D 3 1
3  Hi A 8 1
4  Hi A 9 1
Ben
fuente
2
La respuesta aceptada no funciona cuando mis columnas son o factor de tipo (o algo así) y quiero ordenar de forma descendente para esta columna de factor seguida de una columna entera de forma ascendente. ¡Pero esto funciona bien! ¡Gracias!
Saheel Godhane
10
¿Por qué "solo"? Encuentro que data.table es dd[order(-z, b)]bastante fácil de usar y recordar.
Matt Dowle
2
De acuerdo, no hay mucho entre esos dos métodos, y también data.tablees una gran contribución Ren 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.
Ben
77
Para mí todo se reduce al hecho de que arrange()es completamente declarativo, dd[order(-z, b)]no lo es.
Mullefa
83

El paquete R data.tableproporciona 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ón setorder()desde entonces. Desde v1.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:

require(plyr)
require(doBy)
require(data.table)
require(dplyr)
require(taRifx)

set.seed(45L)
dat = data.frame(b = as.factor(sample(c("Hi", "Med", "Low"), 1e8, TRUE)),
                 x = sample(c("A", "D", "C"), 1e8, TRUE),
                 y = sample(100, 1e8, TRUE),
                 z = sample(5, 1e8, TRUE), 
                 stringsAsFactors = FALSE)

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).

orderBy( ~ -z + b, data = dat)     ## doBy
plyr::arrange(dat, desc(z), b)     ## plyr
arrange(dat, desc(z), b)           ## dplyr
sort(dat, f = ~ -z + b)            ## taRifx
dat[with(dat, order(-z, b)), ]     ## base R

# convert to data.table, by reference
setDT(dat)

dat[order(-z, b)]                  ## data.table, base R like syntax
setorder(dat, -z, b)               ## data.table, using setorder()
                                   ## setorder() now also works with data.frames 

# R-session memory usage (BEFORE) = ~2GB (size of 'dat')
# ------------------------------------------------------------
# Package      function    Time (s)  Peak memory   Memory used
# ------------------------------------------------------------
# doBy          orderBy      409.7        6.7 GB        4.7 GB
# taRifx           sort      400.8        6.7 GB        4.7 GB
# plyr          arrange      318.8        5.6 GB        3.6 GB 
# base R          order      299.0        5.6 GB        3.6 GB
# dplyr         arrange       62.7        4.2 GB        2.2 GB
# ------------------------------------------------------------
# data.table      order        6.2        4.2 GB        2.2 GB
# data.table   setorder        4.5        2.4 GB        0.4 GB
# ------------------------------------------------------------
  • data.tableLa DT[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 que dplyr.

  • data.table's setorder()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 . datahora 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:

    DF <- DF[order(...)]

    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.tables by reference ( en el lugar ), sin hacer copias adicionales. Solo usa memoria adicional igual al tamaño de una columna.

Otras características:

  1. Es compatible integer, logical, numeric, charactere incluso los bit64::integer64tipos.

    Tenga en cuenta que factor, Date, POSIXctclases, etc .. son todos integer/ numerictipos por debajo con atributos adicionales y por lo tanto se apoyan también.

  2. 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)]o setorder(dat, -x).

Arun
fuente
Gracias por esta respuesta muy instructiva sobre data.table. Sin embargo, no entiendo qué es la "memoria máxima" y cómo la calculó. ¿Podría explicar por favor? Gracias !
Julien Navarra
Utilicé Instrumentos -> asignaciones e informé el tamaño de "Todo el montón y la asignación de VM".
Arun
2
El enlace @Arun the Instruments en tu comentario está muerto. ¿Quieres publicar una actualización?
MichaelChirico
@MichaelChirico Aquí hay un enlace a información sobre instrumentos fabricados por Apple: developer.apple.com/library/content/documentation/…
n1k31t4
73

Con esta función (muy útil) de Kevin Wright , publicada en la sección de consejos de R wiki, esto se logra fácilmente.

sort(dd,by = ~ -z + b)
#     b x y z
# 4 Low C 9 2
# 2 Med D 3 1
# 1  Hi A 8 1
# 3  Hi A 9 1
Christopher DuBois
fuente
2
Vea mi respuesta para la evaluación comparativa del algoritmo utilizado en esta función.
Ari B. Friedman
39

o puedes usar el paquete doBy

library(doBy)
dd <- orderBy(~-z+b, data=dd)
George Dontas
fuente
39

Suponga que tiene un data.frame Ay desea ordenarlo usando una columna llamada xorden descendente. Llamar a los ordenadosdata.frame newdata

newdata <- A[order(-A$x),]

Si desea un orden ascendente, reemplácelo "-"con nada. Puedes tener algo como

newdata <- A[order(-A$x, A$y, -A$z),]

donde xy zson algunas columnas en data.frame A. Esto significa ordenar data.frame Apor xdescendente, yascendente y zdescendente.

Khayelihle
fuente
32

Si SQL es algo natural para usted, el sqldfpaquete se encarga de lo ORDER BYque Codd pretendía.

malecki
fuente
77
MJM, gracias por señalar este paquete. Es increíblemente flexible y debido a que la mitad de mi trabajo ya se realiza extrayendo de las bases de datos sql, es más fácil que aprender gran parte de la sintaxis intuitiva de R.
Brandon Bertelsen
31

Alternativamente, usando el paquete Deducer

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))
Ian Fellows
fuente
19

En respuesta a un comentario agregado en el OP sobre cómo ordenar mediante programación:

Usando dplyrydata.table

library(dplyr)
library(data.table)

dplyr

Simplemente use arrange_, que es la versión de Evaluación estándar para arrange.

df1 <- tbl_df(iris)
#using strings or formula
arrange_(df1, c('Petal.Length', 'Petal.Width'))
arrange_(df1, ~Petal.Length, ~Petal.Width)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.4         3.9          1.3         0.4  setosa
7           5.5         3.5          1.3         0.2  setosa
8           4.4         3.0          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...


#Or using a variable
sortBy <- c('Petal.Length', 'Petal.Width')
arrange_(df1, .dots = sortBy)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.5         3.5          1.3         0.2  setosa
7           4.4         3.0          1.3         0.2  setosa
8           4.4         3.2          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...

#Doing the same operation except sorting Petal.Length in descending order
sortByDesc <- c('desc(Petal.Length)', 'Petal.Width')
arrange_(df1, .dots = sortByDesc)

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

dt1 <- data.table(iris) #not really required, as you can work directly on your data.frame
sortBy <- c('Petal.Length', 'Petal.Width')
sortType <- c(-1, 1)
setorderv(dt1, sortBy, sortType)
dt1
     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
  1:          7.7         2.6          6.9         2.3 virginica
  2:          7.7         2.8          6.7         2.0 virginica
  3:          7.7         3.8          6.7         2.2 virginica
  4:          7.6         3.0          6.6         2.1 virginica
  5:          7.9         3.8          6.4         2.0 virginica
 ---                                                            
146:          5.4         3.9          1.3         0.4    setosa
147:          5.8         4.0          1.2         0.2    setosa
148:          5.0         3.2          1.2         0.2    setosa
149:          4.3         3.0          1.1         0.1    setosa
150:          4.6         3.6          1.0         0.2    setosa
info_seekeR
fuente
18

Aprendí ordercon el siguiente ejemplo que luego me confundió durante mucho tiempo:

set.seed(1234)

ID        = 1:10
Age       = round(rnorm(10, 50, 1))
diag      = c("Depression", "Bipolar")
Diagnosis = sample(diag, 10, replace=TRUE)

data = data.frame(ID, Age, Diagnosis)

databyAge = data[order(Age),]
databyAge

La única razón por la que funciona este ejemplo es porque orderestá ordenando por vector Age, no por la columna nombrada Ageen data frame data.

Para ver esto, cree un marco de datos idéntico read.tablecon nombres de columna ligeramente diferentes y sin utilizar ninguno de los vectores anteriores:

my.data <- read.table(text = '

  id age  diagnosis
   1  49 Depression
   2  50 Depression
   3  51 Depression
   4  48 Depression
   5  50 Depression
   6  51    Bipolar
   7  49    Bipolar
   8  49    Bipolar
   9  49    Bipolar
  10  49 Depression

', header = TRUE)

La estructura de línea anterior orderya no funciona porque no hay un vector llamado age:

databyage = my.data[order(age),]

La siguiente línea funciona porque orderlas clases en la columna agede my.data.

databyage = my.data[order(my.data$age),]

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.callcó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 una data.frameen R. Entonces, pensé que mi versión ampliada de ese do.callcódigo original podría ser útil.

set.seed(1234)

v1  <- c(0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1)
v2  <- c(0,0,0,0, 1,1,1,1, 0,0,0,0, 1,1,1,1)
v3  <- c(0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1)
v4  <- c(0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1)

df.1 <- data.frame(v1, v2, v3, v4) 
df.1

rdf.1 <- df.1[sample(nrow(df.1), nrow(df.1), replace = FALSE),]
rdf.1

order.rdf.1 <- rdf.1[do.call(order, as.list(rdf.1)),]
order.rdf.1

order.rdf.2 <- rdf.1[do.call(order, rev(as.list(rdf.1))),]
order.rdf.2

rdf.3 <- data.frame(rdf.1$v2, rdf.1$v4, rdf.1$v3, rdf.1$v1) 
rdf.3

order.rdf.3 <- rdf.1[do.call(order, as.list(rdf.3)),]
order.rdf.3
Mark Miller
fuente
44
Esa sintaxis funciona si almacena sus datos en data.table, en lugar de data.frame: 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 [].
Frank
No creo que el voto negativo sea necesario aquí, pero tampoco creo que esto agregue mucho a la pregunta en cuestión , particularmente teniendo en cuenta el conjunto existente de respuestas, algunas de las cuales ya capturan el requisito con data.frames para usar witho $.
A5C1D2H2I1M1N2O1R2T1
1
El voto a favor de do.callesto hace un trabajo corto de ordenar un marco de datos de varias columnas. Simplemente do.call(sort, mydf.obj)y se tendrá una hermosa especie de cascada.
AdamO
17

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:

dd <- dd[with(dd, order(-z, b)), ] 
Andrés
fuente
13

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

dd1 <- dd %>%
    arrange(z) %>%
    arrange(desc(x))
Kaden Killpack
fuente
7

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:

ind <- do.call(what = "order", args = iris[,c(5,1,2,3)])
iris[ind, ]

##        Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
##    14           4.3         3.0          1.1         0.1     setosa
##    9            4.4         2.9          1.4         0.2     setosa
##    39           4.4         3.0          1.3         0.2     setosa
##    43           4.4         3.2          1.3         0.2     setosa
##    42           4.5         2.3          1.3         0.3     setosa
##    4            4.6         3.1          1.5         0.2     setosa
##    48           4.6         3.2          1.4         0.2     setosa
##    7            4.6         3.4          1.4         0.3     setosa
##    (...)
Dominic Comtois
fuente
6

En aras de la exhaustividad: también puede utilizar la sortByCol()función del BBmiscpaquete:

library(BBmisc)
sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE))
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

Comparación de rendimiento:

library(microbenchmark)
microbenchmark(sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE)), times = 100000)
median 202.878

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=100000)
median 148.758

microbenchmark(dd[with(dd, order(-z, b)), ], times = 100000)
median 115.872
Lars Kotthoff
fuente
44
extraño agregar una comparación de rendimiento cuando su método es el más lento ... de todos modos dudoso el valor de usar un punto de referencia en una fila 4data.frame
MichaelChirico
5

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.

 dd <- dd[order(dd$b, decreasing = FALSE),]

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.

dd <- dd[order(dd$z, decreasing = TRUE),]

Puede que este no sea el más rápido, pero sin duda es simple y confiable.

Almiar
fuente
4

Otra alternativa, usando el rgrpaquete:

> library(rgr)
> gx.sort.df(dd, ~ -z+b)
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1
Stéphane Laurent
fuente
4

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 psychpaquete para hacer esto de una manera directa:

dfOrder(myDf, columnIndices)

donde columnIndicesestá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'

AHegde
fuente