7
votes

Ordre aléatoire des groupes dans la table de données R tout en préservant l'ordre interne des groupes

Dans R, j'ai l'exemple de tableau de données suivant:

# Output (as desired):

    Group InternalOrder RandomGroupID
 1:    d5             1             1
 2:    d5             2             1
 3:    d5             3             1
 4:    d2             1             2
 5:    d3             1             3
 6:    d3             2             3
 7:    d1             1             4
 8:    d1             2             4
 9:    d1             3             4
10:    d1             4             4
11:    d4             1             5
12:    d7             1             6
13:    d7             2             6
14:    d7             3             6
15:    d7             4             6
16:    d7             5             6
17:    d6             1             7

Ce qui ressemble à ceci:

groupsizes <- x[, .N, by = Group]$N  # Get number of elements (= rows) for each group
set.seed(10)
x[, RandomGroupID := rep(sample(c(1:length(unique(x$Group))), replace = F), groupsizes)]  # Make new column with random ID for each group
setorder(x, RandomGroupID, InternalOrder)  # Re-order data by random group ID and internal order

Mon objectif est de randomiser l'ordre des groupes dans la table de données x tout en préservant l'ordre interne de chaque groupe.

J'ai déjà élaboré une solution

# Input:
#
    Group InternalOrder
 1:    d1             1
 2:    d1             2
 3:    d1             3
 4:    d1             4
 5:    d2             1
 6:    d3             1
 7:    d3             2
 8:    d4             1
 9:    d5             1
10:    d5             2
11:    d5             3
12:    d6             1
13:    d7             1
14:    d7             2
15:    d7             3
16:    d7             4
17:    d7             5

qui donne le résultat souhaité:

library(data.table)
x <- data.table(Group = c("d1", "d1", "d1", "d1", "d2", "d3", "d3", "d4", "d5", "d5", "d5", "d6", "d7", "d7", "d7", "d7", "d7"))
x[, InternalOrder := seq(.N), by = Group]

Puisque j'essaie d'améliorer mes compétences en matière de table de données, j'aimerais savoir s'il existe une solution plus agréable et plus idiomatique qui ne nécessite pas l'étape intermédiaire de créer le vecteur groupements mais attribue une nouvelle colonne en utilisant la syntaxe typique de la table de données en utilisant l'argument by en combinaison avec .GRP ou .I ou similaire. J'ai pensé à quelque chose comme x [ RandomGroupIDAlternative: = rep (sample (c (1: length (unique (x $ Group))), replace = F), .GRP), by = Group] code > qui, de toute évidence, ne donne pas le résultat souhaité.

J'ai hâte de recevoir vos commentaires et de voir des solutions alternatives à ce problème.


0 commentaires

3 Réponses :


3
votes

Voici une possibilité:

    Group InternalOrder RandomGroupID
 1:    d1             1             4
 2:    d1             2             4
 3:    d1             3             4
 4:    d1             4             4
 5:    d2             1             7
 6:    d3             1             6
 7:    d3             2             6
 8:    d4             1             1
 9:    d5             1             2
10:    d5             2             2
11:    d5             3             2
12:    d6             1             5
13:    d7             1             3
14:    d7             2             3
15:    d7             3             3
16:    d7             4             3
17:    d7             5             3

Sortie:

x[, RandomGroupID := runif(1), by = Group ]
x[order(RandomGroupID), RandomGroupID := as.numeric(.GRP), by = Group]


0 commentaires

5
votes

Cela peut être fait de manière idiomatique en rejoignant une liste aléatoire de groupes.

x[sample(unique(Group)), on = "Group"][, RandomGroupID := .GRP, by = Group][]


1 commentaires

Excellente solution, merci. J'ai complètement oublié le paramètre "on", qui est en effet assez puissant.



5
votes

Vous pouvez également le faire en utilisant split et rbindlist:

x_new <- rbindlist(sample(split(x, by='Group')))

    Group InternalOrder
 1:    d4             1
 2:    d1             1
 3:    d1             2
 4:    d1             3
 5:    d1             4
 6:    d5             1
 7:    d5             2
 8:    d5             3
 9:    d6             1
10:    d7             1
11:    d7             2
12:    d7             3
13:    d7             4
14:    d7             5
15:    d3             1
16:    d3             2
17:    d2             1


0 commentaires