Supposons que j'ai un bloc de données avec 3 colonnes (name
, y
, sex
) où name
est un caractère, y
est un numérique value et sex
est un facteur.
sex<-c("M","M","F","M","F","M","M","M","F")
x<-c("MARK","TOM","SUSAN","LARRY","EMMA","LEONARD","TIM","MATT","Violet")
name<-as.character(x)
y<-rnorm(9,8,1)
score<-data.frame(x,y,sex)
score
name y sex
1 MARK 6.767086 M
2 TOM 7.613928 M
3 SUSAN 7.447405 F
4 LARRY 8.040069 M
5 EMMA 8.306875 F
6 LEONARD 8.697268 M
7 TIM 10.385221 M
8 MATT 7.497702 M
9 Violet 10.177969 F
Si je voulais le commander par y
j'utiliserais:
score[order(score$y),]
x y sex
1 MARK 6.767086 M
3 SUSAN 7.447405 F
8 MATT 7.497702 M
2 TOM 7.613928 M
4 LARRY 8.040069 M
5 EMMA 8.306875 F
6 LEONARD 8.697268 M
9 Violet 10.177969 F
7 TIM 10.385221 M
Jusqu'ici, tout va bien ... Les noms gardent le bon score MAIS comment pourrais-je le réorganiser pour que les niveaux M et F ne soient pas mélangés. Je dois commander et en même temps garder les niveaux de facteurs séparés.
Enfin, je voudrais aller plus loin pour impliquer le caractère, l'exemple n'aide pas, mais que se passerait-il s'il y avait des valeurs y
liées et que je devrais commander à nouveau dans facteur (par exemple TIM et TOM ont obtenu 8.4 et Je dois attribuer un ordre alphabétique).
Je pensais par fonction mais cela crée une liste et n'aide pas vraiment. Je pense qu'il doit y avoir une fonction comme celle-ci à appliquer sur les trames de données et à obtenir des trames de données en retour.
POUR EFFACER LE POINT:
sep<-split(score,score$sex)
sep$M<-sep$M[order(sep$M[,2]),]
sep$M
x y sex
1 MARK 6.767086 M
8 MATT 7.497702 M
2 TOM 7.613928 M
4 LARRY 8.040069 M
6 LEONARD 8.697268 M
7 TIM 10.385221 M
sep$F<-sep$F[order(sep$F[,2]),]
sep$F
x y sex
3 SUSAN 7.447405 F
5 EMMA 8.306875 F
9 Violet 10.177969 F
merged<-rbind(sep$M,sep$F)
merged
x y sex
1 MARK 6.767086 M
8 MATT 7.497702 M
2 TOM 7.613928 M
4 LARRY 8.040069 M
6 LEONARD 8.697268 M
7 TIM 10.385221 M
3 SUSAN 7.447405 F
5 EMMA 8.306875 F
9 Violet 10.177969 F
Je sais comment faire ça si j'ai 2 ou 3 facteurs. Mais que faire si j'avais des niveaux de facteurs sérieux, disons 20, dois-je écrire une boucle for
?
order
prend plusieurs arguments et fait exactement ce que vous voulez:
with(score, score[order(sex, y, x),])
## x y sex
## 3 SUSAN 6.636370 F
## 5 EMMA 6.873445 F
## 9 Violet 8.539329 F
## 6 LEONARD 6.082038 M
## 2 TOM 7.812380 M
## 8 MATT 8.248374 M
## 4 LARRY 8.424665 M
## 7 TIM 8.754023 M
## 1 MARK 8.956372 M
Voici un résumé de toutes les méthodes mentionnées dans d'autres réponses/commentaires (pour servir les futurs chercheurs). J'ai ajouté une méthode de tri data.table.
# Base R
do.call(rbind, by(score, score$sex, function(x) x[order(x$y),]))
with(score, score[order(sex, y, x),])
score[order(score$sex,score$x),]
# Using plyr
arrange(score, sex,y)
ddply(score, c('sex', 'y'))
# Using `data.table`
library("data.table")
score_dt <- setDT(score)
# setting a key works just fine
setkey(score_dt,sex,x)
print(score_dt)
# Explicitly ordering using i
score_dt[i=order(sex,x),]
Je pense qu'il doit y avoir une fonction comme celle-ci à appliquer sur les trames de données et à obtenir des trames de données en retour
Oui il y a:
library(plyr)
ddply(score, c('y', 'sex'))
Il me semble que vous essayez d'ordonner par score parmi les hommes et les femmes et de renvoyer une base de données combinée de hommes et de femmes triés.
Vous avez raison de dire que by(score, score$sex, function(x) x[order(x$y),])
renvoie une liste de trames de données triées, une pour les hommes et une pour les femmes. Vous pouvez utiliser do.call
avec la fonction rbind
pour combiner ces trames de données en une seule trame de données finale:
do.call(rbind, by(score, score$sex, function(x) x[order(x$y),]))
# x y sex
# F.5 EMMA 7.526866 F
# F.9 Violet 8.182407 F
# F.3 SUSAN 9.677511 F
# M.4 LARRY 6.929395 M
# M.8 MATT 7.970015 M
# M.7 TIM 8.297137 M
# M.6 LEONARD 8.845588 M
# M.2 TOM 9.035948 M
# M.1 MARK 10.082314 M