Reputation: 1061
Extending this former question, how can I shuffle (randomize) the following vector
a1 = c(1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 5, 5)
in order to get something like this:
a2 = c(5, 5, 3, 3, 3, 3, 1, 1, 2, 4, 4, 4)
or even better like this:
a3 = c(4, 4, 4, 2, 3, 3, 3, 3, 1, 1, 5, 5)?
such that each element could randomly change to another but with keeping the number of each element constant?
Upvotes: 1
Views: 120
Reputation: 263301
Seems like a perfect application for rle
and its inverse rep
:
rand_inverse_rle <- function(x) { x=sort(x)
ord=sample (length(rle(x)$values) )
unlist( mapply( rep, rle(x)$values[ord], rle(x)$lengths[ord]))}
rand_inverse_rle(a1)
#----------
[1] 3 3 4 5 5 5 2 2 2 2 1 1
This was my reading of a function needed to satisfy the natural language requirements:
> a1 = sample( c(1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 5, 5) )
> a1
[1] 5 2 5 2 5 1 3 4 2 2 3 1
> rand_inverse_rle(a1)
[1] 5 5 5 4 2 2 2 2 3 3 1 1
> rand_inverse_rle(a1)
[1] 1 1 3 3 5 5 5 2 2 2 2 4
> rand_inverse_rle(a1)
[1] 1 1 3 3 4 5 5 5 2 2 2 2
Upvotes: 3
Reputation: 81683
The data:
a1 <- c(1, 1, 2, 2, 2, 2, 3, 3, 4, 5, 5, 5)
First steps:
# extract values and their frequencies
val <- unique(a1)
tab <- table(a1)
freq <- tab[as.character(val)]
rep(sample(val), freq)
# [1] 4 4 1 1 1 1 3 3 5 2 2 2
rep(sa <- sample(val), freq[as.character(sa)])
# [1] 4 2 2 2 2 3 3 1 1 5 5 5
Upvotes: 3
Reputation: 214927
You can try something like this: create a factor from a1
with randomly shuffled levels and then convert it to integers:
as.integer(factor(a1, levels = sample(unique(a1), length(unique(a1)))))
# [1] 5 5 4 4 4 4 3 3 2 1 1 1
Upvotes: 4