【问题标题】:Random unique binary matrices随机唯一二进制矩阵
【发布时间】:2017-06-08 14:08:33
【问题描述】:

我想要随机但唯一的维度为 n*n 的二进制矩阵。

例如,如果 n = 5,则有 2^(5*5) = 33554432 个唯一组合(矩阵),这是一个巨大的数字。我只需要 1000。这是我目前的方法,但需要很多时间(我负担不起,因为我将来需要增加尺寸)。而且我觉得这是多余的,因为最后我只从完整的数字中选择了 1000 个随机组合。还有其他方法来处理这个吗?这就是我目前的做法:

我从一个包含 n*n 个变量的数据框开始,第一行全为 1,第二行全为 0:

 Length = 25
 m <- as.data.frame(matrix(c(rep(0, connections), rep(1, 
      connections)),ncol=25, byrow = TRUE))

m 看起来像这样:

#V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20 V21 
#V22 V23 V24 V25
#1  0  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0   
#0   0   0   0   0
#2  1  1  1  1  1  1  1  1  1   1   1   1   1   1   1   1   1   1   1   1   
#1   1   1   1   1

接下来我使用 expand.grid 获得所有独特的组合

mFull = expand.grid(m) # This takes forever

然后我随机选择 1000 行:

mRand = mFull[sample(1:nrow(mFull), 1000,)]

在此之后,我将每一行转换为一个 n*n 矩阵,例如,对于第一行:

mRand[1,]
#     V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20 
#V21 V22 V23 V24 V25
#21788869  1  1  0  1  1  1  0  0  1   1   1   0   0   0   0   1   1   1   0   
#0   1   1   0   1   0    

将其转换为矩阵:

> matrix(mRand[1,], nrow = 5, byrow = TRUE)
 [,1] [,2] [,3] [,4] [,5]
 [1,] 1    1    0    1    1   
 [2,] 1    0    0    1    1   
 [3,] 1    0    0    0    0   
 [4,] 1    1    1    0    0   
 [5,] 1    1    0    1    0   

有人对更有效的解决方案提出建议吗?

【问题讨论】:

  • 生成 1000 个二进制矩阵,然后检查是否有任何重复。如果你确实产生更多。重复直到它们都是独一无二的。当 n=5 时,您最初选择的 1000 个选项大约有 98.5% 的可能性是唯一的

标签: r matrix combinations permutation


【解决方案1】:

我建议您完全随机生成矩阵并检查每个新矩阵是否已经创建。如果没有,请丢弃它。

只要可能的矩阵数量比所需的矩阵数量大很多,这样就可以很好地工作,否则可能会很慢。

示例代码:

randomMatrix <- function(n) matrix(as.numeric(runif(n^2) > 0.5), ncol = n)  # generates random binary square matrix of size n x n

m <- 1000  # number of matrices needed

res <- vector("list", m)  # stores the result
i <- 1  # index of next matrix

while (i <= m) {

  cand <- randomMatrix(5)
  ## check if the candidate is distinct from all matrices in res
  if (!any(sapply(res, function(x) identical(x, cand)))) {  
    res[[i]] <- cand
    i <- i + 1
  }

}

如果您真的遇到速度问题(我对此表示怀疑),您可以使用一些哈希来加快比较速度。例如,您可以存储每个矩阵的行和列总和,并且仅在总和一致时测试是否相等。

【讨论】:

    【解决方案2】:

    只要可能的矩阵数量适合整数,您就可以将每个矩阵编码为整数的二进制表示。因此,如果您对整数进行采样而不进行替换,然后将这些整数转换为二进制矩阵,您就完成了。

    这里有几个函数:

    binmat <- function(dec,n){
        matrix(as.integer(intToBits(dec)[1:(n*n)]),n,n)
    
    }
    rbinmats <- function(n,m){
        max = 2^(m*m)
        stopifnot(max < .Machine$integer.max)
    
        m_decimal = sample(max,n)-1
    
        lapply(m_decimal, binmat, n=m)
    
    }
    

    binmat 是这样工作的:

    > binmat(123,3)
         [,1] [,2] [,3]
    [1,]    1    1    1
    [2,]    1    1    0
    [3,]    0    1    0
    

    这只是 123 (001111011) 的 9 位二进制表示,写成矩阵(向后)。

    rbinmats 只是采样并创建这种形式的随机矩阵:

    > rbinmats(4,3)
    [[1]]
         [,1] [,2] [,3]
    [1,]    1    0    1
    [2,]    0    1    0
    [3,]    0    1    0
    
    [[2]]
         [,1] [,2] [,3]
    [1,]    0    0    0
    [2,]    1    1    0
    [3,]    1    1    1
    
    [[3]]
         [,1] [,2] [,3]
    [1,]    1    1    1
    [2,]    0    1    0
    [3,]    0    1    0
    
    [[4]]
         [,1] [,2] [,3]
    [1,]    1    0    0
    [2,]    0    0    1
    [3,]    1    0    1
    

    这里是从 0 到 (2^9)-1 采样 4 个整数,不替换,编码,所以它们是唯一的。

    5x5 似乎是整数中最大的值,因为 2^(5*5) 小于 max int,但 2^(6*6) 不是。除非有办法用 64 位数字做到这一点。

    【讨论】:

    • 但我需要将数字 5 增加到更大的数字!
    • 然后您可以通过为每个矩阵随机选择多个整数来修改此方法。每个整数得到 32 位。对于 8x8 矩阵的任何内容,两个整数将为您提供 64 位。代码需要一些工作,但一般方法是合理的。你想要多大?
    • 这是个好主意。我事先不知道我将来真正需要多少。但我一定会试一试。
    猜你喜欢
    • 2020-08-31
    • 2015-11-26
    • 2011-12-30
    • 2020-03-16
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    相关资源
    最近更新 更多