在没有连续相同数字的r中进行采样

时间:2013-04-04 18:03:30

标签: r

我对R很新,但我已经做了很多搜索,但没有找到答案。

我有一个多次重复8位数的向量:

allNum <- c(rep(1, 70), rep(2, 70), rep(3, 35), rep(4, 35), 
            rep(5, 70), rep(6, 70), rep(7, 35), rep(8, 35))

现在我想对此进行排列(大概使用sample(allNum, 420, replace=FALSE)),但我不想要任何连续的相同数字 - 例如:1 2 2 8

有一种简单的方法吗?

3 个答案:

答案 0 :(得分:3)

您遇到的问题是,有可能随意选择元素而不是选择约束。特别是,如果您必须选择的元素数量超过$ 2n-1 $,其中$ n $是最常见元素出现的次数,您可以选择一个随机元素(与先前的约束一致)。但是,如果这些数字相等,则最频繁的值必须在序列的其余部分的每隔一个位置(并且可以随机分配之间的值)。识别此约束允许单次传递(不再是原始矢量中的元素的随机选择)。

permute.nonconsec <- function(allNum) {
  fully.constrained <- function(x) {
    2*max(table(x)) - 1 == length(x)
  }
  permuted <- numeric(length(allNum))
  permuted[1] <- sample(allNum, 1)
  allNum <- allNum[-min(which(allNum==permuted[1]))]
  for (i in seq_along(allNum)+1) {
    if(fully.constrained(allNum)) {
      # switch to deterministic algorithm
      # determine which value is the constraining one
      r <- rle(sort(allNum))
      limiter <- r$values[r$lengths==max(r$lengths)]
      permuted[seq(i, length(permuted), by=2)] <- limiter
      remaining <- allNum[allNum != limiter]
      if (length(remaining)>0) {
        permuted[seq(i+1, length(permuted), by=2)] <- 
          remaining[sample.int(length(remaining))]
      }
      break;
    }
    available <- allNum[allNum != permuted[i-1]]
    permuted[i] <- available[sample.int(length(available), 1)]
    allNum <- allNum[-min(which(allNum==permuted[i]))]
  }
  permuted
}

如果没有可能的安排,这将失败:length(x) < 2 * max(table(x)) - 1,但如果需要,可以添加初步检查。

答案 1 :(得分:0)

借用a previous answer,一种方法是蛮力并继续采样,直到你获得具有所需特征的排列。

nonconsec.permute <- function(pop,size) {
  while(!exists("x",inherits=FALSE) || 0 %in% diff(x)) {
    x <- sample(pop, size, replace=F)
  }
}

但是,以下命令需要很长时间,因为在您提供的示例中,相同的连续数字非常常见。因此,这种方法在您的具体情况下是不可行的。

nonconsec.permute(allNum,420)

答案 2 :(得分:0)

这是一个简单的算法:

N = 420
i = as.integer(runif(1, 1, length(allNum)))
result = allNum[i]
allNum = allNum[-i]
while (N != 1) {
  N = N - 1

  # pick a random value that's different from last chosen one
  last = result[length(result)]
  i = as.integer(runif(1, 1, sum(allNum != last)))
  result = c(result, allNum[allNum != last][i])

  # remove any (doesn't matter which) element of allNum that's
  # equal to last choice, to sample without replacement
  last = result[length(result)]
  allNum = allNum[-which(allNum == last)[1]]
}