生成n个区域中k球的所有可能结果(多项式/分类结果的总和)

时间:2016-06-08 19:59:35

标签: python numpy scipy permutation combinatorics

假设我们有n个投掷箱,我们投掷k球。什么是快速(即使用numpy / scipy而不是python代码)的方式来生成所有可能的结果作为矩阵?

例如,如果n = 4k = 3,我们需要以下numpy.array

3 0 0 0
2 1 0 0
2 0 1 0
2 0 0 1
1 2 0 0
1 1 1 0
1 1 0 1
1 0 2 0
1 0 1 1
1 0 0 2
0 3 0 0
0 2 1 0
0 2 0 1
0 1 2 0
0 1 1 1
0 1 0 2
0 0 3 0
0 0 2 1
0 0 1 2
0 0 0 3

如果错过任何排列,请道歉,但这是一般的想法。生成的排列不必具有任何特定的顺序,但上面的列表便于在心理上明确地迭代它们。

更好的是,有没有办法将每个从1到multiset number的整数(此列表的基数)直接映射到给定的排列?

这个问题与以下问题有关,这些问题在R中实现,具有非常不同的设施:

还有相关参考文献:

4 个答案:

答案 0 :(得分:1)

这是使用itertools.combinations_with_replacement的生成器解决方案,不知道它是否适合您的需求。

def partitions(n, b):
    masks = numpy.identity(b, dtype=int)
    for c in itertools.combinations_with_replacement(masks, n): 
        yield sum(c)

output = numpy.array(list(partitions(3, 4)))
# [[3 0 0 0]
#  [2 1 0 0]
#  ...
#  [0 0 1 2]
#  [0 0 0 3]]

这个函数的复杂性呈指数级增长,因此在可行和不可行之间存在着一个独立的边界。

请注意,虽然numpy数组需要在构造时知道它们的大小,但这很容易实现,因为很容易找到多重编号。 下面可能是一个更好的方法,我没有做任何时间。

from math import factorial as fact
from itertools import combinations_with_replacement as cwr

nCr = lambda n, r: fact(n) / fact(n-r) / fact(r)

def partitions(n, b):
    partition_array = numpy.empty((nCr(n+b-1, b-1), b), dtype=int)
    masks = numpy.identity(b, dtype=int)
    for i, c in enumerate(cwr(masks, n)): 
        partition_array[i,:] = sum(c)
    return partition_array

答案 1 :(得分:1)

出于参考目的,以下代码使用Ehrlich's algorithm来迭代C ++,Javascript和Python中多集的所有可能组合:

  

https://github.com/ekg/multichoose

可以使用this method将其转换为上述格式。具体地,

for s in multichoose(k, set):
    row = np.bincount(s, minlength=len(set) + 1)

这仍然不是纯粹的numpy,但可以很快用于填充预分配的numpy.array

答案 2 :(得分:0)

这是一个带有列表推导的天真实现,与numpy

相比,不确定性能
judgeScoreList = judgeScores.split()

答案 3 :(得分:0)

这是我为此提出的解决方案。

import numpy, itertools
def multinomial_combinations(n, k, max_power=None):
    """returns a list (2d numpy array) of all length k sequences of 
    non-negative integers n1, ..., nk such that n1 + ... + nk = n."""
    bar_placements = itertools.combinations(range(1, n+k), k-1)
    tmp = [(0,) + x + (n+k,) for x in bar_placements]
    sequences =  numpy.diff(tmp) - 1
    if max_power:
        return sequences[numpy.where((sequences<=max_power).all(axis=1))][::-1]
    else:
        return sequences[::-1]

注1:最后的[:: - 1]只是反转顺序以匹配您的示例输出。

注2:找到这些序列相当于找到排列n个星和k-1个条的所有方法(填充n + k-1个点)(见stars and bars thm 2)。

注3:max_power参数是为您提供仅返回所有整数低于某个最大值的序列的选项。