4
votes

Tri d'une variable dans un bloc de données par identifiant

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 :


2
votes

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


0 commentaires

3
votes

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)


0 commentaires

6
votes

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


0 commentaires

8
votes

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


4 commentaires

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.



3
votes

Dans la base 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

ou comme @Markus le suggère:

split(df, df$id) <- by(df, df$id, function(x) x[order(x$var1),])

sortie dans les deux cas:

split(df,df$id) <- lapply(split(df,df$id), function(x) x[order(x$var1),] )


0 commentaires