J'ai un bloc de données avec beaucoup d'informations sur la société séparées par une variable id. Je veux trier l'une des variables et la répéter pour chaque identifiant. Prenons cet exemple,
id var1 var2 1 110 21 12 2 110 26 234 3 110 54 43 4 90 9 19 5 90 10 32 6 90 16 16 7 90 18 21 8 252 39 44 9 252 54 34
Ce qui ressemble à ceci
> apply(df, 2, sort)
id var1 var2
[1,] 90 9 12
[2,] 90 10 16
[3,] 90 16 19
[4,] 90 18 21
[5,] 110 21 32
[6,] 110 26 34
[7,] 110 39 43
[8,] 252 54 44
[9,] 252 54 234
Maintenant, je veux trier le bloc de données selon var1 par le vecteur id . La solution la plus simple à laquelle je puisse penser est d'utiliser la fonction apply comme celle-ci,
df id var1 var2 1 110 26 234 2 110 21 12 3 110 54 43 4 90 10 32 5 90 18 21 6 90 9 19 7 90 16 16 8 252 54 34 9 252 39 44
Cependant, ce n'est pas le résultat que je recherche. La sortie correcte doit être,
df <- structure(list(id = c(110, 110, 110, 90, 90, 90, 90, 252, 252
), var1 = c(26, 21, 54, 10, 18, 9, 16, 54, 39), var2 = c(234,
12, 43, 32, 21, 19, 16, 34, 44)), .Names = c("id", "var1", "var2"
), row.names = c(NA, -9L), class = "data.frame")
Grouper par id et trier par var1 colonne et strong > conserver l'ordre d'origine des colonnes id .
Avez-vous une idée de comment trier comme ça?
5 Réponses :
Avec le tube tidyverse suivant, la sortie de la question est reproduite.
library(tidyverse) df %>% mutate(tmp = cumsum(c(0, diff(id) != 0))) %>% group_by(id) %>% arrange(tmp, var1) %>% select(-tmp) ## A tibble: 9 x 3 ## Groups: id [3] # id var1 var2 # <dbl> <dbl> <dbl> #1 110 21 12 #2 110 26 234 #3 110 54 43 #4 90 9 19 #5 90 10 32 #6 90 16 16 #7 90 18 21 #8 252 39 44 #9 252 54 34
Nous pouvons convertir l ' id en factor afin de le fractionner tout en préservant la commande d'origine. Nous pouvons ensuite parcourir la liste et l'ordre, et rbind à nouveau, c'est-à-dire
df$id <- factor(df$id, levels = unique(df$id)) do.call(rbind, lapply(split(df, df$id), function(i)i[order(i$var1),])) # id var1 var2 #110.2 110 21 12 #110.1 110 26 234 #110.3 110 54 43 #90.6 90 9 19 #90.4 90 10 32 #90.7 90 16 16 #90.5 90 18 21 #252.9 252 39 44 #252.8 252 54 34
REMARQUE: Vous pouvez réinitialiser les noms de rôle par noms de domaine (new_df)
Une autre option de base R utilisant order et match
df[with(df, order(match(id, unique(id)), var1, var2)), ] # id var1 var2 #2 110 21 12 #1 110 26 234 #3 110 54 43 #6 90 9 19 #4 90 10 32 #7 90 16 16 #5 90 18 21 #9 252 39 44 #8 252 54 34
Remarque. Comme mentionné par Moody_Mudskipper, il n'est pas nécessaire d'utiliser tidyverse et peut également être fait facilement avec la base R :
# [1,] 90 9 12
En base R votre solution deviendrait df [order (factor (df $ id, unique (df $ id)), df $ var1),] (j'utilise facteur au lieu de ordonné car ordonné n'est pas nécessaire, plus long à taper et moins connu).
Certes, ordonné est plus long que le facteur mais à mon humble avis, sémantiquement plus clair. Un facteur n'a qu'une commande implicite tandis que commandé en a une explicite. R n'est pas cohérent ici je dirais: min (factor (1: 3, 3: 1)) ne fonctionne pas pour des raisons évidentes, mais sort (factor (1: 3, 3: 1)) le fait, car le facteur est traité silencieusement comme un numérique.
À mon avis, commandé est quelque chose que j'utiliserais pour les modèles, pour agréger des valeurs ( range , min , max , median , quantile , ...), ou pour organiser les catégories ggplot, donc je vois son utilisation ici comme une complexité supplémentaire, mais je vois votre point (pertinent: stackoverflow.com/questions/23396591/factors-ordered-vs-leve Ls /… ). Mais je suis pinailleur (et voté depuis le début).
Bonne lecture +1. Je pense que sort (factor (.)) fonctionne pour des raisons héritées plutôt qu'intentionnelles. Je peux difficilement imaginer comment vous définiriez un algorithme de tri sans opérations de comparaison. À un moment donné, il était trop tard pour résoudre ce problème et c'est maintenant un code R valide. Mon opinion est que je veux être explicite plutôt qu'implicite pour rendre mon code plus compréhensible. C'est pourquoi tidyverse` gagne pour moi sur data.table , à moins que les performances ne soient un frein.
Dans la base ou comme @Markus le suggère: sortie dans les deux cas: R , nous pourrions utiliser split : df
# id var1 var2
# 1 110 21 12
# 2 110 26 234
# 3 110 54 43
# 4 90 9 19
# 5 90 10 32
# 6 90 16 16
# 7 90 18 21
# 8 252 39 44
# 9 252 54 34
split(df, df$id) <- by(df, df$id, function(x) x[order(x$var1),])
split(df,df$id) <- lapply(split(df,df$id), function(x) x[order(x$var1),] )
N'est-ce pas simplement
df%>% arrange (id, var1)dansdplyr?Double possible de Comment trier un dataframe par plusieurs colonnes? < / a>
Je ne crois pas que ce soit une dupe, du moins pas celle-là. L'OP demande un moyen de trier par groupes de
id.Pourquoi
id - 110est-il le premier? quelle est la logique du tri?La colonne @Sotos
idne doit pas être triée, seulevar1est, dans chaque groupe deid.