R: cómo muestrear sin reemplazo Y sin los mismos valores consecutivos

10

He pasado más de un día tratando de lograr lo que parece ser algo muy simple. Tengo que crear 300 secuencias 'aleatorias' en las que los números 1,2,3 y 4 aparecen exactamente 12 veces, pero el mismo número nunca se usa dos veces 'en una fila' / consecutivamente.

Mis mejores intentos (supongo) fueron:

  1. haga que R muestre 48 elementos sin reemplazo, pruebe si hay valores consecutivos con rle, luego use solo las secuencias que no contienen valores consecutivos. Problema: casi no hay secuencias aleatorias que cumplan este criterio, por lo que lleva una eternidad.

  2. haga que R cree secuencias sin valores consecutivos (vea el código).

pop<-rep(1:4,12)
y=c()
while(length(y)!=48)
  {
  y= c(y,sample(pop,48-length(y),replace=F))
  y=y[!c(FALSE, diff(y) == 0)]
  }

Problema: esto crea secuencias con números variables de cada valor. Luego intenté usar solo esas secuencias con exactamente 12 de cada valor, pero eso solo me trajo de vuelta al problema 1: toma una eternidad.

Debe haber alguna manera fácil de hacer esto, ¿verdad? ¡Cualquier ayuda es muy apreciada!

CookieMons
fuente

Respuestas:

3

Quizás usarlo replicate()con un repeatbucle sea más rápido. Aquí un ejemplo con 3secuencias. Parece que esto tomaría aprox. 1490 segundos con 300(no probado).

set.seed(42)
seqc <- rep(1:4, each=12)  # starting sequence

system.time(
  res <- replicate(3, {
    repeat {
      seqcs <- sample(seqc, 48, replace=FALSE) 
      if (!any(diff(seqcs) == 0)) break
    }
    seqcs
  })
)
#  user  system elapsed 
# 14.88    0.00   14.90 

res[1:10, ]
#       [,1] [,2] [,3]
#  [1,]    4    2    3
#  [2,]    1    1    4
#  [3,]    3    2    1
#  [4,]    1    1    4
#  [5,]    2    3    1
#  [6,]    4    1    2
#  [7,]    3    4    4
#  [8,]    2    1    1
#  [9,]    3    4    4
# [10,]    4    3    2
jay.sf
fuente
1
Muchas gracias! Crear 100 secuencias tomó 800 segundos, lo cual es completamente aceptable en este caso. Resuelto mi problema!
CookieMons
1

Otra opción es utilizar un método de Markov Chain Monte-Carlo para intercambiar 2 números al azar y pasar a la nueva muestra solo cuando 1) no estamos intercambiando el mismo número y 2) no hay 2 números idénticos adyacentes. Para abordar muestras correlacionadas, podemos generar muchas muestras y luego seleccionar aleatoriamente 300 de ellas:

v <- rep(1:4, 12)
l <- 48
nr <- 3e5
m <- matrix(0, nrow=nr, ncol=l)
count <- 0
while(count < nr) {
    i <- sample(l, 2)
    if (i[1L] != i[2L]) {
        v[i] = v[i[2:1]]
        if (!any(diff(v)==0)) {
            count <- count + 1
            m[count, ] <- v
        } else {
            v[i] = v[i[2:1]]
        }
    }
}
a <- m[sample(nr, 300),]
a
chinsoon12
fuente
1

Puede sacar valores consecutivos y colocarlos donde no son consecutivos.

unConsecutive  <- function(x) {
    repeat{
        tt <- c(FALSE, diff(x)==0)
        if(any(tt)) {
            y <- x[which(tt)]
            x <- x[which(!tt)]
            i <- x != y[1]
            i  <- which(c(c(TRUE, diff(i)==0) & i,FALSE)
                        | c(FALSE, c(diff(i)==0, TRUE) & i))
            if(length(i) > 0) {
                i <- i[1]-1
                x <- c(x[seq_len(i)], y, x[i+seq_len(length(x)-i)])
            } else {
                x  <- c(x, y)
                break
            }
        } else {break}
    }
    x
}

unConsecutive(c(1,1,2))
#[1] 1 2 1
unConsecutive(c(1,1,1))
#[1] 1 1 1

set.seed(7)
system.time(
    res <- replicate(300, unConsecutive(sample(rep(1:4,12))))
)
#   user  system elapsed 
#  0.058   0.011   0.069 
all(apply(res, 2, table) == 12)
#[1] TRUE
all(apply(res, 2, diff) != 0)
#[1] TRUE
GKi
fuente