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 - 110
est-il le premier? quelle est la logique du tri?La colonne @Sotos
id
ne doit pas être triée, seulevar1
est, dans chaque groupe deid
.