【问题标题】:Shuffling a vector - all possible outcomes of sample()?洗牌向量 - sample() 的所有可能结果?
【发布时间】:2013-12-18 23:44:15
【问题描述】:

我有一个包含五个项目的向量。

my_vec <- c("a","b","a","c","d")

如果我想将这些值重新排列到一个新的向量中(随机播放),我可以使用 sample():

shuffled_vec <- sample(my_vec)

简单 - 但 sample() 函数只给了我一种可能的随机播放。 如果我想知道所有可能的洗牌组合怎么办?各种“combn”函数似乎没有帮助,expand.grid() 给了我所有可能的组合有替换,当我需要它没有替换。最有效的方法是什么?

请注意,在我的向量中,我的值“a”两次 - 因此,在返回的洗牌向量集中,它们都应该在集合中都有两次“a”。

【问题讨论】:

  • 您能对您现在的 3 个答案提供一些反馈吗?

标签: r shuffle sampling


【解决方案1】:

查看上一个问题(R: generate all permutations of vector without duplicated elements),我可以看到gtools 包有一个功能。但是,我无法将其直接用于您的矢量:

permutations(n = 5, r = 5, v = my_vec)
#Error in permutations(n = 5, r = 5, v = my_vec) : 
#  too few different elements

你可以这样调整它:

apply(permutations(n = 5, r = 5), 1, function(x) my_vec[x])

#     [,1] [,2] [,3] [,4] 
#[1,] "a"  "a"  "a"  "a" ...
#[2,] "b"  "b"  "b"  "b" ...
#[3,] "a"  "a"  "c"  "c" ... 
#[4,] "c"  "d"  "a"  "d" ...
#[5,] "d"  "c"  "d"  "a" ... 

【讨论】:

    【解决方案2】:

    我认为组合包中的 permn 可以满足您的需求

    library(combinat)
    permn(my_vec)
    

    一个小例子

    > x
    [1] "a" "a" "b"
    > permn(x)
    [[1]]
    [1] "a" "a" "b"
    
    [[2]]
    [1] "a" "b" "a"
    
    [[3]]
    [1] "b" "a" "a"
    
    [[4]]
    [1] "b" "a" "a"
    
    [[5]]
    [1] "a" "b" "a"
    
    [[6]]
    [1] "a" "a" "b"
    

    如果重复是一个问题,您可以执行类似的操作来消除重复

    strsplit(unique(sapply(permn(my_vec), paste, collapse = ",")), ",")
    

    或者可能是删除重复项的更好方法...

    dat <- do.call(rbind, permn(my_vec))
    dat[duplicated(dat),]
    

    【讨论】:

      【解决方案3】:

      注意到您的数据实际上是从 1 到 5 的 5 个级别,编码为“a”、“b”、“a”、“c”和“d”,我开始寻找方法来获取数字 1-5,然后将它们重新映射到您使用的级别。

      让我们从输入数据开始:

      my_vec <- c("a","b","a","c","d") # the character
      my_vec_ind <- seq(1,length(my_vec),1) # their identifier
      

      为了得到排列,我应用了Generating all distinct permutations of a list in R 给出的函数:

      permutations <- function(n){
        if(n==1){
          return(matrix(1))
        } else {
          sp <- permutations(n-1)
          p <- nrow(sp)
          A <- matrix(nrow=n*p,ncol=n)
          for(i in 1:n){
            A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))
          }
          return(A)
        }
      }
      

      首先,使用排列创建一个 data.frame:

      tmp <- data.frame(permutations(length(my_vec)))
      

      您现在有一个包含 120 行的数据框 tmp,其中每一行都是数字 1-5 的唯一排列:

      >tmp
          X1 X2 X3 X4 X5
      1    1  2  3  4  5
      2    1  2  3  5  4
      3    1  2  4  3  5
      ...
      119  5  4  3  1  2
      120  5  4  3  2  1
      

      现在您需要将它们重新映射到您拥有的字符串。您可以使用gsub() 主题的变体重新映射它们,此处建议:R: replace characters using gsub, how to create a function?

      gsub2 <- function(pattern, replacement, x, ...) {
        for(i in 1:length(pattern))
          x <- gsub(pattern[i], replacement[i], x, ...)
        x
      }
      

      gsub() 不起作用,因为替换数组中有多个值。

      您还需要一个可以使用lapply() 调用的函数,以便在tmp data.frame 的每个元素上使用gsub2() 函数。

      remap <- function(x, 
                    old,
                    new){
        return(gsub2(pattern = old, 
                    replacement = new, 
                    fixed = TRUE,
                    x = as.character(x)))
      }
      

      差不多了。我们像这样进行映射:

      shuffled_vec <- as.data.frame(lapply(tmp, 
                                remap,
                                old = as.character(my_vec_ind), 
                                new = my_vec))
      

      可以简化为...

      shuffled_vec <- as.data.frame(lapply(data.frame(permutations(length(my_vec))), 
                                remap,
                                old = as.character(my_vec_ind), 
                                new = my_vec))
      

      .. 如果你觉得有必要。

      这给了你所需的答案:

      > shuffled_vec
          X1 X2 X3 X4 X5
      1    a  b  a  c  d
      2    a  b  a  d  c
      3    a  b  c  a  d
      ...
      119  d  c  a  a  b
      120  d  c  a  b  a
      

      【讨论】:

      • 即使 OP 没有回复,我也有一个非常相似的问题,发现这非常有用。但是,我还有一个额外的后续问题......这个问题只有 5 个元素,但是对于元素更多的情况,速度显然是一个问题。此外,对于此类问题的大多数应用,我们只需要说 10,000 个返回的排列。是否可以修改此代码以仅返回最多 10,000 个唯一权限?
      • 如果您想要 10,000 个随机采样排列,请使用类似 tmp &lt;- tmp[ sample(1:NROW(tmp), 10000, replace=F),]
      猜你喜欢
      • 2022-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-25
      • 2021-10-05
      • 2013-10-20
      • 2021-05-04
      相关资源
      最近更新 更多