生成0和1排列的有效方法?

时间:2015-08-06 16:17:22

标签: r algorithm permutation

我想要做的是在给定特定样本大小的情况下生成1和0的所有可能排列。例如,对于n = 8的样本,我希望m = 2 ^ 8 = 256种可能的排列,即:

documentation

我在R中编写了一个函数来执行此操作,但是在n = 11之后需要很长时间才能运行。我更喜欢R中的解决方案,但如果它在另一种编程语言中,我可能会想出来。谢谢!

PermBinary <- function(n){ 
  n.perms <- 2^n 
  array <- matrix(0,nrow=n,ncol=n.perms) 
  # array <- big.matrix(n, n.perms, type='integer', init=-5) 
  for(i in 1:n){ 
    div.length <- ncol(array)/(2^i) 
    div.num <- ncol(array)/div.length 
    end <- 0 
      while(end!=ncol(array)){ 
        end <- end +1 
        start <- end + div.length 
        end <- start + div.length -1 
        array[i,start:end] <- 1 
      } 
   } 
   return(array) 
} 

2 个答案:

答案 0 :(得分:4)

expand.grid可能是获得你想要的最佳工具。

例如,如果您希望样本大小为3,我们可以执行类似

的操作
expand.grid(0:1, 0:1, 0:1)

样本量为4

expand.grid(0:1, 0:1, 0:1, 0:1)

所以我们想要做的就是找到一种自动化调用的方法。

如果我们有一个我们想要提供给expand.grid的输入列表,我们可以使用do.call为我们构建调用。例如

vals <- 0:1
tmp <- list(vals, vals, vals)
do.call(expand.grid, tmp)

所以现在的挑战是自动制作上面的“tmp”列表,我们可以决定我们想要多少份“vals”。有很多方法可以做到这一点,但一种方法是使用replicate。由于我们需要一个列表,我们需要告诉它不要简化结果,否则我们将得到一个矩阵/数组作为结果。

vals <- 0:1
tmp <- replicate(4, vals, simplify = FALSE)
do.call(expand.grid, tmp)

或者我们可以在列表输入上使用rep(我认为它更快,因为它没有复制的开销,但我没有测试过它)

tmp <- rep(list(vals), 4)
do.call(expand.grid, tmp)

现在将其包装成一个函数来获取:

binarypermutations <- function(n, vals = 0:1){
    tmp <- rep(list(vals), n)
    do.call(expand.grid, tmp)
}

然后调用样本大小,如binarypermutations(5)

这样就得到了一个尺寸为2 ^ n x n的data.frame - 如果您愿意,可以转置并转换为不同的数据类型。

答案 1 :(得分:3)

上面的答案可能会更好,因为它使用base - 我的第一个想法是使用data.table的CJ函数:

library(data.table)
do.call(CJ, replicate(8, c(0, 1), FALSE))

它会比expand.grid稍微快一些(~15%),所以它对于极端情况只会更有价值。