当向量很大时,如何获得R中向量的所有可能分区的列表?

时间:2013-01-13 16:31:22

标签: r vector combinatorics

我正在尝试使用R来查找将长度为x的向量n分区为最多m个分区的所有可能方法。我知道当n很小时该怎么做:

library(partitions)
x <- c(10, 20, 30, 40)
n <- length(x)
m <- 3

# In how many ways can we partition n objects into at most m patitions
parts <- restrictedparts(n, m)
sets <- setparts(parts)

在此示例中,sets的值为:

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

sets的每一列都告诉我,对于每个独特的安排,应该在x中分配每个项目的分区。

n很大时会出现问题:

n <- 15
m <- 4
parts <- restrictedparts(n, m)
# This expression will max out your CPU usage and eventually run out of memory.
sets <- setparts(parts)

如何在不耗尽内存的情况下执行此操作?我怀疑有一个快速的方法,所以我怀疑我必须分批进行并写入磁盘。

3 个答案:

答案 0 :(得分:3)

如果像我一样,你不是组合学中的超级巨星,但你相信partitions说得对,那么至少你可以利用包的代码来计算最终的分区数。在这里,我攻击了setparts函数,因此,它不是分区本身,而是返回分区数:

num.partitions <- function (x) {
    if (length(x) == 1) {
        if (x < 1) {
            stop("if single value, x must be >= 1")
        }
        else if (x == 1) {
            out <- 1
        }
        else return(Recall(parts(x)))
    }
    if (is.matrix(x)) {
        out <- sum(apply(x, 2, num.partitions))
    }
    else {
        x   <- sort(x[x > 0], decreasing = TRUE)
        out <- factorial(sum(x))/(prod(c(factorial(x), 
                                         factorial(table(x)))))
    }
    return(out)
}

让我们检查函数是否返回了正确数量的分区:

num.partitions(restrictedparts(4, 3))
# [1] 14
ncol(setparts(restrictedparts(4, 3)))
# [1] 14

num.partitions(restrictedparts(8, 4))
# [1] 2795
ncol(setparts(restrictedparts(8, 4)))
# [1] 2795

现在让我们来看看你的大案:

num.partitions(restrictedparts(15, 4))
# [1] 44747435

确实有很多分区......无论写出setparts的好坏,输出都不适合单个数组:

sets <- matrix(1, 15, 44747435)
# Error in matrix(1, 15, 44747435) : 
#  cannot allocate vector of length 671211525

所以是的,您必须编写自己的算法并存储到矩阵列表中,或者如果它对您的内存来说太多,请写入文件,如果这真的是您想要做的。否则,考虑到相当多的排列以及你想要用它们做什么,请回到绘图板......

答案 1 :(得分:1)

如果您想分批计算它们,看起来这可能至少对某些列来说是可能的。我无法在像您这样的机器上完成restrictedparts(15,4)中几个单独列的计算。直到第40列,我一次可以成功地批量生成5-10列,但是高于这一点,有几个单列在抛出malloc错误之前报告了多个列。所以你可能只需要一台更大的机器。在我的Mac上,32 GB构造第53列消耗了一半的内存。大机器上的列数估计与4GB机器上的报告一致:

> ncol( setparts( restrictedparts(15,4)[,53]))
[1] 6306300
R(317,0xa077a720) malloc: *** mmap(size=378380288) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

(我不会就这是否是一个明智的项目提出意见。)

答案 2 :(得分:0)

由于我无法安装分区包(缺少库),我想出了这个:

 ## Recursive function to get all partitions of a vector 
 ## Returns a list of logical vectors
 parts <- function(x) { 
   if (length(x) == 1) return(list(FALSE, TRUE))
   do.call(c, lapply(parts(x[-1]), function(y) list(c(FALSE, y), c(TRUE, y))))
 }

此函数采用向量并返回相同大小的逻辑向量列表。列表中的向量数是可能的分区数(2 ^ n)。它无法处理巨大的n,但在我的电脑上它在不到一秒的时间内运行n = 19。

如果您只想要非空分区,并且没有重复项,请使用:

 partitions <- parts(x)
 partitions <- partitions[1:(length(partitions)/2)][-1]