按顺序生成排列-R

时间:2019-05-08 16:19:50

标签: r performance permutation

我之前问过以下问题 Permutation of n bernoulli random variables in R

只要n相对较小(<30),此问题的答案就很有效,否则会出现以下错误代码错误:无法分配大小为4.0 Gb的向量。通过在工作中使用桌面,我可以使代码以更大的值运行,但最终会出现相同的错误。即使对于我的计算机可以处理的值(例如25),代码也非常慢。

此代码的目的是计算精确分布的CDF(因此发生排列)与正态近似值之间的差。我随机生成一些数据,计算测试统计量,然后我需要通过将所有导致较小的测试统计量值除以排列总数的排列求和来确定CDF。

我的想法是一次只生成一个排列列表,请注意它是否小于我的观察值,然后继续执行下一个,即遍历所有可能的排列,但是我不能只拥有循环遍历所有排列的数据帧,因为那样会导致大小和速度完全相同。

长话短说:我需要为n个bernoulli试验生成1和0的所有可能排列,但是我需要一次执行一次,以便全部生成,并且对于任意n都不会生成一次以上。对于n = 3,2 ^ 3 = 8,我首先生成

000

计算我的测试统计数据是否大于(1或0),然后生成

001

再次计算,然后生成

010

计算,然后生成

100

计算,然后生成

011

等到111

我很好,这是一个遍历2 ^ n的循环,它在循环的每一步都输出排列,但不会将它们全部保存在某个地方。同样,我也不关心它们的生成顺序,上面只是我手工完成这些操作的方式。

此外,如果仍然可以加快以前的代码的速度,那也将有所帮助。

1 个答案:

答案 0 :(得分:2)

迭代器是解决您的问题的一个好方法。有一个名为arrangements的程序包,它能够以迭代方式生成排列。观察:

library(arrangements)

# initialize iterator 
iperm <- ipermutations(0:1, 3, replace = T)

for (i in 1:(2^3)) {
    print(iperm$getnext())
}

[1] 0 0 0
[1] 0 0 1
.
.
.
[1] 1 1 1

它是用C编写的,非常有效。您还可以一次生成m个排列,如下所示:

iperm$getnext(m)

由于下一个排列是由C中的for循环而不是R中的for循环生成的,因此可以提供更好的性能。

如果您确实需要提高性能,可以使用parallel软件包。

iperm <- ipermutations(0:1, 40, replace = T)

parallel::mclapply(1:100, function(x) {
    myPerms <- iperm$getnext(10000)
    # do something
}, mc.cores = parallel::detectCores() - 1)

注意:所有代码都未经测试。