2011-10-11 10 views
7

He encontrado una aplicación donde necesito ordenar un data.frame por números de columna, y ninguno de los usual solutions parece permitir eso.Ordenar en una lista

El contexto está creando un método as.data.frame.by. Como un objeto by tendrá su última columna como columna de valor y las primeras columnas ncol-1 como columnas de índice. melt lo devuelve ordenado al revés - índice 3, luego índice 2, luego índice 1. Para compatibilidad con latex.table.by Me gustaría ordenarlo hacia adelante. Pero estoy teniendo problemas para hacerlo de una manera suficientemente genérica. La línea comentada en la siguiente función es mi mejor intento hasta ahora.

as.data.frame.by <- function(x, colnames=paste("IDX",seq(length(dim(x))),sep=""), ...) { 
    num.by.vars <- length(dim(x)) 
    res <- melt(unclass(x)) 
    res <- na.omit(res) 
    colnames(res)[seq(num.by.vars)] <- colnames 
    #res <- res[ order(res[ , seq(num.by.vars)]) , ] # Sort the results by the by vars in the heirarchy given 
    res 
} 

dat <- transform(ChickWeight, Time=cut(Time,3), Chick=cut(as.numeric(Chick),3)) 
my.by <- by(dat, with(dat,list(Time,Chick,Diet)), function(x) sum(x$weight)) 
> as.data.frame(my.by) 
      IDX1   IDX2 IDX3 value 
1 (-0.021,6.99] (0.951,17.3] 1 3475 
2  (6.99,14] (0.951,17.3] 1 5969 
3  (14,21] (0.951,17.3] 1 8002 
4 (-0.021,6.99] (17.3,33.7] 1 640 
5  (6.99,14] (17.3,33.7] 1 1596 
6  (14,21] (17.3,33.7] 1 2900 
13 (-0.021,6.99] (17.3,33.7] 2 2253 
14  (6.99,14] (17.3,33.7] 2 4734 
15  (14,21] (17.3,33.7] 2 7727 
22 (-0.021,6.99] (17.3,33.7] 3 666 
23  (6.99,14] (17.3,33.7] 3 1391 
24  (14,21] (17.3,33.7] 3 2109 
25 (-0.021,6.99] (33.7,50] 3 1647 
26  (6.99,14] (33.7,50] 3 3853 
27  (14,21] (33.7,50] 3 7488 
34 (-0.021,6.99] (33.7,50] 4 2412 
35  (6.99,14] (33.7,50] 4 5448 
36  (14,21] (33.7,50] 4 8101 

Con la línea no comentada, devuelve un galimatías (que sólo trata a todo el hoja.de.datos como un vector, con resultados desastrosos).

Incluso he intentado cosas inteligentes como res <- res[ order(...=list(res[,1],res[,2])) , ] pero fue en vano.

Sospecho que hay una manera simple de hacer esto, pero no lo estoy viendo.

Editar para aclarar: No quiero tener que especificar los nombres de las columnas. En cambio, quiero poder ordenarlo por un vector numérico (por ejemplo, ordenar por columnas 1: 4).

Respuesta

7
mydf <- as.data.frame(my.by) 
mydf[order(mydf$IDX3, mydf$IDX2, mydf$IDX1) , ] 
      IDX1   IDX2 IDX3 value 
1 (-0.021,6.99] (0.951,17.3] 1 3475 
3  (14,21] (0.951,17.3] 1 8002 
2  (6.99,14] (0.951,17.3] 1 5969 
4 (-0.021,6.99] (17.3,33.7] 1 640 
6  (14,21] (17.3,33.7] 1 2900 
5  (6.99,14] (17.3,33.7] 1 1596 
13 (-0.021,6.99] (17.3,33.7] 2 2253 
15  (14,21] (17.3,33.7] 2 7727 
14  (6.99,14] (17.3,33.7] 2 4734 
22 (-0.021,6.99] (17.3,33.7] 3 666 
24  (14,21] (17.3,33.7] 3 2109 
23  (6.99,14] (17.3,33.7] 3 1391 
25 (-0.021,6.99] (33.7,50] 3 1647 
27  (14,21] (33.7,50] 3 7488 
26  (6.99,14] (33.7,50] 3 3853 
34 (-0.021,6.99] (33.7,50] 4 2412 
36  (14,21] (33.7,50] 4 8101 
35  (6.99,14] (33.7,50] 4 5448 

O;

my.by <- by(dat, with(dat,list(Diet,Chick, Time)), function(x) sum(x$weight)) 
mydf <- as.data.frame(my.by) 

EDIT: O esto produce mismo resultado que en la superior utilizando los índices de columna numérica:

mydf <- as.data.frame(my.by) 
mydf[ do.call(order, mydf[, 3:1]) , ] 
+0

sentimos que debería haber sido más claro: Quiero no tener que especificar nombres de columna. En cambio, quiero poder ordenarlo por un vector numérico (por ejemplo, ordenar por columnas 1: 4). –

+0

Ver arriba. El método do.call de pasar dataframes a 'order' se ilustra en la página' help (order) '. –

+0

Agradable. Gracias. Necesito mirar más de cerca en 'do.call', ya que sospecho que resolvería muchos de mis problemas :-) –