在R中存储所有可能的排列

时间:2018-04-09 05:59:44

标签: r

我在“gtools”下使用permutations命令。但是,它产生了记忆问题。

我尝试了以下内容:

library(gtools)
permutations(n=15,r=8)

但是,我收到以下错误消息:

 Error in next_permutations(n, k, -1L, NULL, x, freq, replace, type) : 
cannot allocate vector of length 2075673600.

这是我正在做的事情的基础。我需要的排名远远超过n=15k=8

1 个答案:

答案 0 :(得分:2)

我之前的回答有两个缺点:

  • 它只计算1:r
  • 的排列
  • 由于我使用了n! / r!而不是n! / (n - r)!,因此排列的数量是错误的。

最后一点将n = 15r = 8的结果矩阵的大小增加了8到8 GB。这突出了Ben Bolker在评论中提出的观点:人们应该考虑以迭代的方式完成排列。

无论如何,生成所有排列的简单方法是首先使用combn()生成所有组合。之后,可以使用C ++中的std::next_permutation生成每个组合的排列:

src1 <- '
IntegerMatrix permute_combinations(const IntegerMatrix& combs) {
  size_t numComb(combs.cols());
  size_t r(combs.rows());
  size_t numPermPerComb(1);
  for(size_t i = 1; i <= r; ++i) numPermPerComb *= i;
  size_t numPerm = numComb * numPermPerComb;
  IntegerMatrix perms(numPerm, r);

  for(size_t i = 0; i < numComb; ++i) {
    IntegerVector v = combs(_, i);
    for (size_t j = 0; j < numPermPerComb; ++j) {
      perms(i * numPermPerComb + j, _) = v;
      std::next_permutation(v.begin(), v.end());
    }
  }
  return perms;
}
'

Rcpp::cppFunction(src1)
system.time(perms <- permute_combinations(combn(15, 8)))
#>        User      System verstrichen 
#>      54.572       1.136      56.006
dim(perms)
#> [1] 259459200         8
object.size(perms)
#> 8302694600 bytes
head(perms)
#>      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#> [1,]    1    2    3    4    5    6    7    8
#> [2,]    1    2    3    4    5    6    8    7
#> [3,]    1    2    3    4    5    7    6    8
#> [4,]    1    2    3    4    5    7    8    6
#> [5,]    1    2    3    4    5    8    6    7
#> [6,]    1    2    3    4    5    8    7    6
tail(perms)
#>              [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#> [259459195,]   15   14   13   12   11    8    9   10
#> [259459196,]   15   14   13   12   11    8   10    9
#> [259459197,]   15   14   13   12   11    9    8   10
#> [259459198,]   15   14   13   12   11    9   10    8
#> [259459199,]   15   14   13   12   11   10    8    9
#> [259459200,]   15   14   13   12   11   10    9    8

原始版本

结果矩阵刚好低于1 GB,因此gtools代码中必须存在一些低效率。这里有一个快速的&amp;用于Rcpp的脏C ++版本:

src <- 'IntegerMatrix permutations(int n, int r) {
  size_t numPerm(1);
  for(int i = n; i > r; --i) {
    numPerm *= i;
  }
  IntegerMatrix result(numPerm, r);

  IntegerVector v(r);
  std::iota (std::begin(v), std::end(v), 1);

  for (size_t i = 0; i < numPerm; ++i) {
    result(i, _) = v;
    std::next_permutation(v.begin(), v.end());
  }
  return result;
}'
Rcpp::cppFunction(src)
system.time(perms <- permutations(15, 8))
#>        User      System verstrichen 
#>       6.909       0.060       6.970
dim(perms)
#> [1] 32432400        8
object.size(perms)
#> 1037837000 bytes
head(perms)
#>      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#> [1,]    1    2    3    4    5    6    7    8
#> [2,]    1    2    3    4    5    6    8    7
#> [3,]    1    2    3    4    5    7    6    8
#> [4,]    1    2    3    4    5    7    8    6
#> [5,]    1    2    3    4    5    8    6    7
#> [6,]    1    2    3    4    5    8    7    6