【问题标题】:How to generate all possible vectors based on sampling without replacement in R?如何基于采样生成所有可能的向量而不在R中替换?
【发布时间】:2019-04-02 20:19:49
【问题描述】:

我有七个数字。我想生成所有长度为 7 的向量:

  • 从 7 个数字的池中抽取两个第一个元素。
  • 从剩下的 5 个数字中抽取两个下一个元素。
  • 从剩下的 3 个数字中抽取三个最终元素。

这种方式可以用向量 c(2,2,3) 来描述。

For example:
sample <- c(8.93,9.11,9.12,9.05,8.87,8.95,9.02)
structure <- c(2,2,3)

我知道有 7C2*5C2*3C3 = 210 个这样的向量。为了更清楚,我不需要在每组元素内进行排列,例如,两个向量 c(8.93,9.11,9.12,9.05,8.87,8.95,9.02)c(9.11,8.93,9.12,9.05,8.87,8.95,9.02) 对我来说是相同的,我只需要其中一个出现在 210 个向量的列表中。

这是我使用 for 循环、combnsetdiff 所做的。但是,我想在代码中使用向量structure 并使其更灵活,例如c(2,5) 而不是c(2,2,3)。有没有更简洁的解决方案来概括我的问题,例如 apply 函数系列?

df<-data.frame()
sample <- c(8.93,9.11,9.12,9.05,8.87,8.95,9.02)
combn(sample,2) -> com1
for (i in 1:ncol(com1)){
    com1[,i]
    setdiff(sample,com1[,i]) -> com2
    combn(com2,2) -> com3
    for (j in 1:ncol(com3)){
    setdiff(com2,com3[,j]) -> com4
    c(com1[,i],com3[,j],com4) -> de
    df <- rbind(df,de)
    }
}
df

【问题讨论】:

  • 你目前有什么代码?
  • @HectorHaffenden 谢谢,我只是用我所做的来更新我的问题。

标签: r combinations


【解决方案1】:

基础 R 中的递归版本:

x <- c(8.93,9.11,9.12,9.05,8.87,8.95,9.02)
k <- c(2, 2, 3)

f <- function(el, l) {
    if (length(l)==1L) {
        return(data.frame(t(el)))
    }

    do.call(rbind, combn(el, l[1L], 
        #using code directly from setdiff for slight speedup and 
        #comparing integers for robustness
        function(s) cbind(data.frame(t(s)), f(el[match(el, s, 0L) == 0L], l[-1L])),
        simplify=FALSE))
}

apply(f(seq_along(x), k), 1L:2L, function(i) x[i])

【讨论】:

    【解决方案2】:

    这是你需要的吗?在“我想生成所有长度为 7 的向量”的问题中感觉像是一个矛盾,但随后又说你只需要 2 个 eg 中的一个。使用combn 会不会只以一个随机样本结束?

    library(combinat)
    x1 <- permn(sample[1:2])
    x2 <- permn(sample[3:4])
    x3 <- permn(sample[5:7])
    
    all <- expand.grid(x1, x2, x3)
    apply(all, 1, unlist)
    

    【讨论】:

    • 非常感谢。我刚刚更新了我的问题,我希望现在变得更清楚。我还包含了代码以获得我的预期结果,但我仍然需要更好的方法。
    【解决方案3】:

    既然你提到了combnsetdiff,这里就有可能:

    1. 我们首先创建一个便利函数draw,它从x 中抽取ndraw 样本并将结果存储在lst 中。

      draw <- function(x, ndraw, lst) {
          unlist(lapply(lst, function(y) {
              lapply(
                  combn(setdiff(x, y), ndraw, simplify = F),
                  function(z) c(y, z))
          }), recursive = F)
      }
      
    2. 然后我们可以定义一个函数generate_samplesdraw,因为x 中的样本数量与draws 中的条目一样多。我添加了一个检查以确保draws 的总和等于x 中的元素数。

      generate_samples <- function(x, draws) {
          stopifnot(sum(draws) == length(x))
          res <- list(NULL)
          for (i in seq_along(draws)) res <- draw(x, draws[i], res)
          res
      }
      
    3. 在您的特定情况下,我们会这样做

      lst <- generate_samples(sample, draws = structure)
      #[[1]]
      #[1] 8.93 9.11 9.12 9.05 8.87 8.95 9.02
      #
      #[[2]]
      #[1] 8.93 9.11 9.12 8.87 9.05 8.95 9.02
      #
      #[[3]]
      #[1] 8.93 9.11 9.12 8.95 9.05 8.87 9.02
      #
      #[[4]]
      #[1] 8.93 9.11 9.12 9.02 9.05 8.87 8.95
      #
      #[[5]]
      #[1] 8.93 9.11 9.05 8.87 9.12 8.95 9.02
      #
      #[[6]]
      #[1] 8.93 9.11 9.05 8.95 9.12 8.87 9.02
      # ....
      
    4. 我们确认这确实在输出 list 中产生了 210 元素

      length(lst)
      #[1] 210
      

    【讨论】:

      【解决方案4】:
      find_combns_in_remainders <- function(list_combns_and_remainders, m) {
        unlist(lapply(
          list_combns_and_remainders,
          function(.) combn(x = .$remainder,
                            m = m,
                            FUN = function(combination) 
                              list(combination = c(.$combination, combination),
                                   remainder = setdiff(.$remainder, combination)),
                            simplify = FALSE)
        ), recursive = FALSE)
      }
      
      Reduce(
        x = structure, 
        f = find_combns_in_remainders, 
        init = list(list(combination = numeric(0), remainder = sample))
      )
      
      # [[1]]
      # [[1]]$combination
      # [1] 8.93 9.11 9.12 9.05 8.87 8.95 9.02
      # 
      # [[1]]$remainder
      # numeric(0)
      # 
      # 
      # [[2]]
      # [[2]]$combination
      # [1] 8.93 9.11 9.12 8.87 9.05 8.95 9.02
      # 
      # [[2]]$remainder
      # numeric(0)
      # 
      # 
      # [[3]]
      # [[3]]$combination
      # [1] 8.93 9.11 9.12 8.95 9.05 8.87 9.02
      # 
      # [[3]]$remainder
      # numeric(0)
      # 
      # 
      # ....
      # 
      # 
      # [[208]]
      # [[208]]$combination
      # [1] 8.95 9.02 9.12 9.05 8.93 9.11 8.87
      # 
      # [[208]]$remainder
      # numeric(0)
      # 
      # 
      # [[209]]
      # [[209]]$combination
      # [1] 8.95 9.02 9.12 8.87 8.93 9.11 9.05
      # 
      # [[209]]$remainder
      # numeric(0)
      # 
      # 
      # [[210]]
      # [[210]]$combination
      # [1] 8.95 9.02 9.05 8.87 8.93 9.11 9.12
      # 
      # [[210]]$remainder
      # numeric(0)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-29
        • 1970-01-01
        相关资源
        最近更新 更多