【问题标题】:Generate list of all possible combinations of elements of vector生成向量元素所有可能组合的列表
【发布时间】:2023-03-29 03:15:01
【问题描述】:

我正在尝试在长度为 14 的向量中生成 0 和 1 的所有可能组合。有没有一种简单的方法可以将该输出作为向量列表,甚至更好的是数据帧?

为了更好地展示我在寻找什么,假设我只想要一个长度为 3 的向量。我希望能够生成以下内容:

 (1,1,1), (0,0,0), (1,1,0), (1,0,0), (1,0,1), (0,1,0), (0,1,1), (0,0,0)

【问题讨论】:

  • 这些是排列顺序问题

标签: r combinations permutation


【解决方案1】:

您正在寻找expand.grid

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

或者,对于长案例:

n <- 14
l <- rep(list(0:1), n)

expand.grid(l)

【讨论】:

    【解决方案2】:

    tidyr 有几个类似于expand.grid() 的选项。

    tidyr::crossing() 返回一个 tibble 并且不将字符串转换为因子(尽管您可以这样做 expand.grid(..., stringsAsFactors = F))。

    library(tidyr)
    
    crossing(var1 = 0:1, var2 = 0:1, var3 = 0:1)
    # A tibble: 8 x 3
       var1  var2  var3
      <int> <int> <int>
    1     0     0     0
    2     0     0     1
    3     0     1     0
    4     0     1     1
    5     1     0     0
    6     1     0     1
    7     1     1     0
    8     1     1     1
    

    tidyr::expand() 可以给出仅出现在数据中的值的两种组合,如下所示:

    expand(mtcars, nesting(vs, cyl))
    # A tibble: 5 x 2
         vs   cyl
      <dbl> <dbl>
    1     0     4
    2     0     6
    3     0     8
    4     1     4
    5     1     6
    

    或两个变量的所有可能组合,即使数据中的数据中没有那些特定值的观察值,像这样:

    expand(mtcars, vs, cyl)
    # A tibble: 6 x 2
         vs   cyl
      <dbl> <dbl>
    1     0     4
    2     0     6
    3     0     8
    4     1     4
    5     1     6
    6     1     8
    

    (可以看到原始数据中没有观察到vs == 1 &amp; cyl == 8

    tidyr::complete() 也可以类似于expand.grid() 使用。这是文档中的一个示例:

    df <- dplyr::tibble(
      group = c(1:2, 1),
      item_id = c(1:2, 2),
      item_name = c("a", "b", "b"),
      value1 = 1:3,
      value2 = 4:6
    )
    df %>% complete(group, nesting(item_id, item_name))
    
    # A tibble: 4 x 5
      group item_id item_name value1 value2
      <dbl>   <dbl> <chr>      <int>  <int>
    1     1       1 a              1      4
    2     1       2 b              3      6
    3     2       1 a             NA     NA
    4     2       2 b              2      5
    

    这为每个组提供了 item_id 和 item_name 的所有可能组合 - 它为 group=2 item_id=1item_name=a 创建一行。

    【讨论】:

      【解决方案3】:

      作为@Justin 方法的替代方案,您还可以使用“data.table”包中的CJ。在这里,我还使用了replicate 来创建包含 14 个 0 和 1 的列表。

      library(data.table)
      do.call(CJ, replicate(14, 0:1, FALSE))
      #        V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14
      #     1:  0  0  0  0  0  0  0  0  0   0   0   0   0   0
      #     2:  0  0  0  0  0  0  0  0  0   0   0   0   0   1
      #     3:  0  0  0  0  0  0  0  0  0   0   0   0   1   0
      #     4:  0  0  0  0  0  0  0  0  0   0   0   0   1   1
      #     5:  0  0  0  0  0  0  0  0  0   0   0   1   0   0
      #    ---                                               
      # 16380:  1  1  1  1  1  1  1  1  1   1   1   0   1   1
      # 16381:  1  1  1  1  1  1  1  1  1   1   1   1   0   0
      # 16382:  1  1  1  1  1  1  1  1  1   1   1   1   0   1
      # 16383:  1  1  1  1  1  1  1  1  1   1   1   1   1   0
      # 16384:  1  1  1  1  1  1  1  1  1   1   1   1   1   1
      

      【讨论】:

      • infravalued 方法根据其速度与众所周知的 expand.grid 相比
      【解决方案4】:

      我在这里讨论一种通用方法来解决所有类似类型的问题,例如这个问题。首先让我们看看解决方案如何随着 N 数量的增加而演变,以找出一般模式。

      首先,长度为1的解是

      0
      1
      

      现在长度为 2,解决方案变为(第 2 列由 | 分隔):

      0 | 0 0, 0 1
      1 | 1 0, 1 1
      

      将其与长度为 1 的先前解决方案进行比较,很明显,要获得此新解决方案,我们只需将 0 和 1 附加到先前解决方案的每个(第一列,0 和 1)。

      现在长度为 3,解决方案是(第 3 列):

      0 | 0 0 | 0 0 0, 0 0 1
      1 | 1 0 | 1 0 0, 1 0 1
        | 0 1 | 0 1 0, 0 1 1
        | 1 1 | 1 1 0, 1 1 1
      

      同样,这个新的解决方案是通过将 0 和 1 附加到每个先前的解决方案(长度为 2 的第 2 列)中获得的。

      这种观察自然会导致递归解决方案。假设我们已经获得了长度 N-1 solution(c(0,1), N-1) 的解,为了获得 N 的解,我们只需将 0 和 1 附加到解 N-1 append_each_to_list(solution(c(0,1), N-1), c(0,1)) 的每一项。请注意这里更复杂的问题(解决 N)如何自然地分解为更简单的问题(解决 N-1)。

      然后我们只需要将这个简单的英语翻译成几乎字面意义上的 R 代码:

      # assume you have got solution for a shorter length len-1 -> solution(v, len-1) 
      # the solution of length len will be the solution of shorter length appended with each element in v 
      solution <- function(v, len) {
        if (len<=1) {
          as.list(v)
        } else {
          append_each_to_list(solution(v, len-1), v)
        } 
      }
      
      # function to append each element in vector v to list L and return a list
      append_each_to_list <- function(L, v) {
        purrr::flatten(lapply(v, 
               function(n) lapply(L, function(l) c(l, n))
               ))
      }
      

      调用函数:

      > solution(c(1,0), 3)
      [[1]]
      [1] 1 1 1
      
      [[2]]
      [1] 0 1 1
      
      [[3]]
      [1] 1 0 1
      
      [[4]]
      [1] 0 0 1
      
      [[5]]
      [1] 1 1 0
      
      [[6]]
      [1] 0 1 0
      
      [[7]]
      [1] 1 0 0
      

      【讨论】:

        【解决方案5】:

        有 16384 种可能的排列。您可以使用iterpc 包迭代获取结果。

        library(iterpc)
        I = iterpc(2, 14, label=c(0,1), order=T, replace=T)
        getnext(I)
        # [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0
        getnext(I)
        # [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 1
        getnext(I)
        # [1] 0 0 0 0 0 0 0 0 0 0 0 0 1 0
        

        如果你想要所有结果,你仍然可以使用getall(I)

        【讨论】:

          【解决方案6】:

          由于您处理的是 0 和 1,因此按照位来考虑整数似乎很自然。使用与此 post(下面的MyIntToBit)略有不同的函数,以及您选择的 apply 函数,我们可以获得所需的结果。

          MyIntToBit <- function(x, dig) {
              i <- 0L
              string <- numeric(dig)
              while (x > 0) {
                  string[dig - i] <- x %% 2L
                  x <- x %/% 2L
                  i <- i + 1L
              }
              string
          }
          

          如果你想要一个列表,请像这样使用lapply

          lapply(0:(2^14 - 1), function(x) MyIntToBit(x,14))
          

          如果您更喜欢矩阵,sapply 可以解决问题:

          sapply(0:(2^14 - 1), function(x) MyIntToBit(x,14))
          

          以下是示例输出:

          > lapply(0:(2^3 - 1), function(x) MyIntToBit(x,3))
          [[1]]
          [1] 0 0 0
          
          [[2]]
          [1] 0 0 1
          
          [[3]]
          [1] 0 1 0
          
          [[4]]
          [1] 0 1 1
          
          [[5]]
          [1] 1 0 0
          
          [[6]]
          [1] 1 0 1
          
          [[7]]
          [1] 1 1 0
          
          [[8]]
          [1] 1 1 1
          
          
          > sapply(0:(2^3 - 1), function(x) MyIntToBit(x,3))
                [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
          [1,]    0    0    0    0    1    1    1    1
          [2,]    0    0    1    1    0    0    1    1
          [3,]    0    1    0    1    0    1    0    1 
          

          【讨论】:

            【解决方案7】:

            这是与先前答案不同的方法。如果您需要 1 和 0 的 14 个值的所有可能组合,这就像生成从 0 到 (2^14)-1 的所有可能数字并保持它们的二进制表示。

            n <- 14
            lapply(0:(2^n-1), FUN=function(x) head(as.integer(intToBits(x)),n))
            

            【讨论】:

            • 这很好(+1),很高兴看到它使用内置函数。但是,它类似于上面 Joseph Wood 的答案(并且在 n = 14 时,他的自定义版本 MyIntToBit 运行速度提高了 3-4 倍)。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-04-01
            • 2017-08-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多