我对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
有一种简单的方法吗?
答案 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]]
}