【问题标题】:R - Add combinations of elements within a vectorR - 在向量中添加元素组合
【发布时间】:2016-07-06 00:05:38
【问题描述】:

有谁知道将向量内的数字组合相加的方法?

假设我正在经历一个 for 循环,并且每次我最终得到一个不同长度的向量,我如何组合这个向量的每个元素,以便我得到 2、3 等元素的总和?

例如,如果我有:

vector <- c(1:5)

并且想通过它:

element 1 + element 2; element 2 + element 3, etc

还有:

element 1 + element 2 + element 3

我该怎么做?重要的是要注意,在许多向量中,长度会有所不同。因此,虽然一个向量可能包含 3 个元素,但另一个向量可能包含 12 个。

我知道你可以做vector[1]+vector[2],但我需要一些方法来遍历整个向量,其中考虑到上述注释。

【问题讨论】:

    标签: r vector


    【解决方案1】:

    使用你可以使用combn:

    > combn(vector, 3, FUN = NULL, simplify = TRUE)
         [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
    [1,]    1    1    1    1    1    1    2    2    2     3
    [2,]    2    2    2    3    3    4    3    3    4     4
    [3,]    3    4    5    4    5    5    4    5    5     5
    

    这里的诀窍是每次调用都会返回一个结果矩阵,您必须决定如何聚合和存储所有各种组合。

    如果你不介意有一个列表,那么下面应该可以解决问题:

    > sapply(c(1:length(vector)),
             function(x) {
                 combn(vector, x, FUN = NULL, simplify = TRUE)
             })
    

    【讨论】:

      【解决方案2】:

      生成对 ID

      在这种情况下,我们需要得到对:

      combn(3, 2)
      

      输出:

           [,1] [,2] [,3]
      [1,]    1    1    2
      [2,]    2    3    3
      

      对是按列生成的。

      对向量元素求和(使用子集)

      为了访问每个元素并执行求和,我们选择定义一个辅助函数来获取组合和向量。

      # Write a helper function 
      # sums of the index of the vector
      comb_subset_sum = function(x, vec){
        return(sum(vec[x]))
      }
      

      由此,我们可以直接使用combn,也可以使用sapply

      求和为 1 k

      combn直接:

      # Input Vector
      vec = 1:5
      
      # Length of vector
      n = length(vec)
      
      # Generate pairwise combinations and obtain pair_sum
      # Specify the k (m in R)
      m = combn(n, m = 2, FUN = comb_subset_sum, vec = vec)
      

      sapply 用法:

      # Input Vector
      vec = 1:5
      
      # Number of Observations
      n = length(vec)
      
      # Combinations
      # Specify the k (m in R)
      combinations = combn(n, m = 2)
      
      # Obtain vectorized sum over subset
      subset_summed = apply(combinations, 2, comb_subset_sum, vec = vec)
      

      示例输出:

      组合

           [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
      [1,]    1    1    1    1    2    2    2    3    3     4
      [2,]    2    3    4    5    3    4    5    4    5     5
      

      subset_summed

       [1] 3 4 5 6 5 6 7 7 8 9
      

      追踪:

      vec[1]+vec[2]=3 
      vec[1]+vec[3]=4 
      vec[1]+vec[4]=5 
      vec[1]+vec[5]=6 
      vec[2]+vec[3]=5 
      vec[2]+vec[4]=6 
      vec[2]+vec[5]=7 
      vec[3]+vec[4]=7 
      vec[3]+vec[5]=8 
      vec[4]+vec[5]=9 
      

      要获取跟踪输出,请在comb_subset_sum() 中的return() 之前添加以下内容:

      cat(paste0("vec[",x,"]", collapse = "+"), "=", sum(vec[x]), "\n")
      

      对多个k求和:

      在这里,我们应用相同的逻辑,只是以使组合的 k 值能够取多个值的方式。

      # Input Vector
      vec = 1:5
      
      # Length of Vec
      n = length(vec)
      
      # Store output
      o = vector('list',n)
      
      for(i in seq_along(vec)){
        o[[i]] = combn(n, i, FUN = comb_subset_sum, vec = vec)
      }
      

      注意:o的每个元素的大小会随着组合数量的增加然后减少而变化。

      对组合求和

      如果我们不关心向量元素的值,我们可以用类似于我们获取向量元素的方式对实际组合进行求和。

      要生成对然后求和,请使用:

      # Input Vector
      vec = 1:5
      
      # Length of Vec
      n = length(vec)
      
      # Generate all combinations (by column)
      # Specify the k (m in R)
      m = combn(n, m = 2)
      
      # Obtain sum by going over columns
      sum_m = apply(m, 2, sum)
      

      或者一次性完成:

      # Specify the k (m in R)
      sum_inplace = combn(n, m = 2, FUN = sum)
      

      平等:

      all.equal(sum_m,sum_inplace)
      

      k 使用次数的总和

      而且,和以前一样,我们可以设置它以获取不同 k 下的所有总和,方法是:

      # Input Vector
      vec = 1:5
      
      # Length of Vec
      n = length(vec)
      
      # Store output (varying lengths)
      o = vector('list',n)
      
      for(i in seq_along(vec)){
        o[[i]] = combn(n, i, FUN = sum)
      }
      

      【讨论】:

      • 嗨。我真的不明白你的答案。在我的问题示例中,最大可能值为 15 (5+4+3+2+1),但是当我运行您的代码时,我得到的一些值高达 40。我只需要一些方法来将所有不同的值相加向量内的元素组合,但在一个 for 循环中,其中向量具有 x 个元素。可能我理解错了?
      • 考虑C(5,3) 通过choose(5,3) 这给出了10 个组合的总数。因此,对于这些组合中的每一个,我们得到一个不同的vec 元素ID。我们使用这些元素 ID 来获取 vec 中的子集,然后在其上使用 sum。因此,对于C(5,3),我们应该有一个长度为10numeric 向量,其中包含10 个不同的向量和。
      • 查看附加跟踪信息@Gotmadstacks 以了解第一位的作用。
      【解决方案3】:

      以下依赖于数字的二进制表示。基本上,您有 2^n 组合要检查。通过使用 'n' 位以二进制形式写入 1 到 2^n 之间的任何数字,您就拥有了您可能想要的所有元素排列。

      number2binary 函数来自 Paul Hiestra 在这方面的回答:How to convert integer number into binary vector?

      number2binary = function(number, noBits) {
        binary_vector = rev(as.numeric(intToBits(number)))
        if(missing(noBits)) {
          return(binary_vector)
        } else {
          binary_vector[-(1:(length(binary_vector) - noBits))]
        }
      }
      
      vector <- 1:5
      
      n <- length(vector)
      
      comp_sum <- function(x) {
        binary <- number2binary(x, noBits = n)
        result <- sum(vector[which(binary==1)])
        names(result) <- paste(which(binary == 1), collapse = "+")
        return(result)
      }
      
      binaries <- sapply(1:2^n-1, comp_sum)
      

      注意:我只上升到 2^n - 1 因为你不需要“零”。通过在 comp_sum 函数中添加一些条件,您可以只选择两个元素或三个元素的总和...

      【讨论】:

        【解决方案4】:

        您可能正在从zoo 包中寻找rollsum,您可以在其中指定要添加的元素数量:

        lapply(2:5, function(i) zoo::rollsum(1:5, i))
        [[1]]
        [1] 3 5 7 9    # two elements roll sum
        
        [[2]]
        [1]  6  9 12   # three elements roll sum
        
        [[3]]
        [1] 10 14      # four elements roll sum
        
        [[4]]
        [1] 15         # five elements roll sum
        

        【讨论】:

          猜你喜欢
          • 2021-11-26
          • 2019-02-23
          • 1970-01-01
          • 2016-11-18
          • 2020-06-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-24
          相关资源
          最近更新 更多