1434 votes

Comment trier une base de données par colonne (s) dans R

Je veux trier un data.frame par plusieurs colonnes dans R. Par exemple, avec le data.frame ci-dessous je voudrais trier par colonne z (descendant) puis par colonne b (ascendant):

 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
 

1739voto

Dirk Eddelbuettel Points 134700

Vous pouvez utiliser l' order() fonction directement, sans recourir à des outils complémentaires -- voir cette simple réponse, qui utilise un truc à droite à partir du haut de l' example(order) code:

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

Edit 2 ans plus tard: C'était juste demandé comment faire cela par un index de colonne. La réponse est tout simplement de passer le tri souhaitée colonne(s) à l' order() fonction de:

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> 

plutôt que d'utiliser le nom de la colonne (et with() de plus facile/plus d'accès direct).

537voto

Ari B. Friedman Points 24940

J'ai récemment ajouté de tri.les données.cadre d'un CRAN paquet, rendant classe compatible comme expliqué ici: Meilleure façon de créer des génériques, de méthode, de cohérence pour le tri.les données.cadre?

Par conséquent, compte tenu des données.cadre de dd, vous pouvez trier comme suit:

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 vous êtes l'un des auteurs de cette fonction, veuillez me contacter. Débat public domaininess est ici: http://chat.stackoverflow.com/transcript/message/1094290#1094290


Vous pouvez également utiliser l' arrange() fonction Hadley souligné dans le fil au-dessus:

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

Critères d'évaluation: la Note que j'ai chargé chaque paquet dans un nouveau R de session car il y avait beaucoup de conflits. En particulier, le chargement de la doBy paquet causes esort de retour "de L'objet suivant(s) sont masqués à partir de 'x (poste 17)': b, x, y, z", et le chargement de la Deducer paquet remplace le tri.les données.cadre de Kevin Wright ou le taRifx paquet.

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

La médiane de temps:

dd [(dd, de l'ordre de (z, b)), ] 778

dd[commande(-jj$z, jj$b)] 788

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

Temps médian: 1,567

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

Temps médian: 862

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

Temps médian: de 1 694

Notez que doBy prend un bon peu de temps pour charger le package.

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

Ne pouvais pas faire Deducer charge. Besoins JGR de la console.

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

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

Ne semble pas être compatible avec microbenchmark en raison de l'attacher/détacher.


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

microbenchmark plot

(lignes s'étendent à partir du premier quartile supérieur quartile, la dot est la médiane)


Compte tenu de ces résultats et de pesage simplicité vs vitesse, je dois donner le clin d'œil à l' arrange dans la plyr package. Il a une syntaxe simple et pourtant il est presque aussi rapide que la base de R des commandes avec leurs alambiqué machinations. Généralement brillant Hadley Wickham travail. Mon seul reproche c'est qu'il se casse la norme R nomenclature où le tri des objets appelés par sort(object), mais je comprends pourquoi Hadley fait de cette façon en raison de problèmes abordés dans la question ci-dessus.

166voto

Matt Dowle Points 20936

Dirk réponse est grande. Il met également en évidence une différence clé dans la syntaxe utilisée pour l'indexation data.frames et 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 différence entre les deux appels est petit, mais il peut avoir d'importantes conséquences. Surtout si vous écrivez le code de production et/ou qui sont concernées par la justesse de votre recherche, il est préférable d'éviter la répétition inutile des noms de variables. data.table vous aide à le faire.

Voici un exemple de comment la répétition des noms de variable pourrait vous causer des ennuis:

Nous allons modifier le contexte de Dirk réponse, et de dire que c'est une partie d'un projet plus large, où il y a beaucoup de noms d'objets et ils sont de longue et significative; au lieu de dd il est appelé quarterlyreport. Il devient :

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

Ok, très bien. Rien de mal à cela. Ensuite, votre patron vous demande d'inclure du trimestre précédent rapport dans le rapport. Vous allez grâce à votre code, l'ajout d'un objet lastquarterlyreport dans divers endroits, et d'une certaine manière (comment?) vous retrouver avec ceci :

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

Ce n'est pas ce que vous voulez dire, mais vous ne l'avais pas remarqué parce que vous l'avez fait rapidement et il est niché sur une page de code similaire. Le code n'est pas de tomber (sans aucun avertissement et sans erreur) car R pense que c'est ce que vous vouliez dire. Que vous espérer que celui qui lit votre rapport de spots, mais peut-être qu'ils n'en ont pas. Si vous travaillez avec des langages de programmation beaucoup, alors cette situation est peut-être tous familiers. C'était une "faute de frappe" que vous allez dire. Je vais corriger la "faute de frappe" que vous allez dire à votre patron.

En data.table nous sommes préoccupés par les petits détails de ce genre. Nous avons donc fait quelque chose de simple pour éviter de taper les noms de variables deux fois. Quelque chose de très simple. i est évaluée dans le cadre d' dd déjà, automatiquement. Vous n'avez pas besoin d' with() .

Au lieu de

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

c'est juste

dd[order(-z, b)]

Et au lieu de

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

c'est juste

quarterlyreport[order(-z,b)]

C'est une très petite différence, mais il pourrait bien sauver votre cou un jour. Quand on regarde les différentes réponses à cette question, considérons compter les répétitions des noms de variables comme l'un de vos critères pour décider. Certaines réponses ont fait quelques répétitions, d'autres n'en ont pas.

145voto

Ben Points 8166

Il y a beaucoup d'excellentes réponses ici, mais dplyr donne la seule syntaxe que je peux rapidement et facilement mémoriser (et que j'utilise maintenant très souvent):

 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)
 

Pour le problème de l'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
 

81voto

Christopher DuBois Points 7589

Avec cette fonction (très utile) de Kevin Wright , publiée dans la section des astuces du wiki R , ceci est facilement réalisable.

 > 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
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X