Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 概率向量上的网格_Python_Numpy_Scientific Computing - Fatal编程技术网

Python 概率向量上的网格

Python 概率向量上的网格,python,numpy,scientific-computing,Python,Numpy,Scientific Computing,我试图得到一个由n维概率向量组成的“网格”——向量中的每个条目都在0到1之间,所有条目加起来等于1。我希望得到每一个可能的向量,其中坐标可以取0到1之间等距值的任意一个v 为了说明这一点,对于n=3和v=3,下面的实现效率极低: from itertools import product grid_redundant = product([0, .5, 1], repeat=3) grid = [point for point in grid_redundant if sum(point)==1

我试图得到一个由n维概率向量组成的“网格”——向量中的每个条目都在0到1之间,所有条目加起来等于1。我希望得到每一个可能的向量,其中坐标可以取0到1之间等距值的任意一个v

为了说明这一点,对于n=3和v=3,下面的实现效率极低:

from itertools import product
grid_redundant = product([0, .5, 1], repeat=3)
grid = [point for point in grid_redundant if sum(point)==1]
现在
网格
包含
[(0,0,1)、(0,0.5,0.5)、(0,1,0)、(0.5,0,0.5)、(0.5,0.5,0)、(1,0,0)]

这种“实现”对于更高维和更细粒度的网格来说是可怕的。有没有一个好方法可以做到这一点,可以使用
numpy



我或许可以在动机上补充一点:如果从随机分布中抽样给我足够的极值点,我会非常高兴,但事实并非如此。看见我所追求的“网格”不是随机的,而是系统地扫描单纯形(概率向量的空间)。

这里是一个递归解决方案。它不使用NumPy,也不是超高效的,尽管它应该比发布的代码段快:

import math
from itertools import permutations

def probability_grid(values, n):
    values = set(values)
    # Check if we can extend the probability distribution with zeros
    with_zero = 0. in values
    values.discard(0.)
    if not values:
        raise StopIteration
    values = list(values)
    for p in _probability_grid_rec(values, n, [], 0.):
        if with_zero:
            # Add necessary zeros
            p += (0.,) * (n - len(p))
        if len(p) == n:
            yield from set(permutations(p))  # faster: more_itertools.distinct_permutations(p)

def _probability_grid_rec(values, n, current, current_sum, eps=1e-10):
    if not values or n <= 0:
        if abs(current_sum - 1.) <= eps:
            yield tuple(current)
    else:
        value, *values = values
        inv = 1. / value
        # Skip this value
        yield from _probability_grid_rec(
            values, n, current, current_sum, eps)
        # Add copies of this value
        precision = round(-math.log10(eps))
        adds = int(round((1. - current_sum) / value, precision))
        for i in range(adds):
            current.append(value)
            current_sum += value
            n -= 1
            yield from _probability_grid_rec(
                values, n, current, current_sum, eps)
        # Remove copies of this value
        if adds > 0:
            del current[-adds:]

print(list(probability_grid([0, 0.5, 1.], 3)))
与已发布方法的快速比较:

from itertools import product

def probability_grid_basic(values, n):
    grid_redundant = product(values, repeat=n)
    return [point for point in grid_redundant if sum(point)==1]

values = [0, 0.25, 1./3., .5, 1]
n = 6
%timeit list(probability_grid(values, n))
1.61 ms ± 20.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit probability_grid_basic(values, n)
6.27 ms ± 186 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

对于高维向量,即使使用公认答案中的巧妙解决方案,在完全通用的情况下这样做也是相当难以管理的。在我自己的例子中,计算所有值的相关子集是值得的。例如,以下函数计算所有
维度
维度概率向量,其中只有
n
非零等概率条目:

import itertools as it
import numpy as np

def equip_n(dimension, n):
"""
Calculate all possible <dimension>-dimensional probability vectors with n nonzero,
equiprobable entries
"""
combinations  = np.array([comb for comb in it.combinations(range(dimension), n)])
vectors = np.zeros((combinations.shape[0], dimension))
for line, comb in zip(vectors, combinations):
    line[comb] = 1/n
return vectors 

print(equip_n(6, 3))
这是非常快的<代码>%timeit设备(6,3)
返回

15.1 µs ± 74.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

@yeputons可能重复,谢谢你的指针。它不是复制品;我对问题进行了编辑,以明确这一点。关于预先确定的概率值,你还能说些什么?它们只是[0,1/(v-1),2/(v-1),…,(v-1)/(v-1)]吗?是的,对不起,我脑子里有均匀分布的值。我编辑了这个问题来反映这一点。@bobrobbob是的,作为一个递归算法,你不需要天文数字大小的输入来打破它。。。我不知道OP期望的实际尺寸是多少,但是…是的3000是疯狂的对不起。如果值更合理,你的结果是错误的。从n=v=6开始,您只返回12个结果(仅包含0/.2/1的组合),而“基本”返回252个结果(包含0/.2/.4/.6/.8/1的组合)@bobrobbob感谢您指出这一点,现在修复了它(这是一个浮点精度错误)。这不是一个解决方案。首先,如果v=3,则从中选择概率的值应为0、0.5和1。第二,如果它不包括所有可能的向量,但只包括其中的一些。例如[1,0,0,0,0,0,0]。
[[ 0.3333  0.3333  0.3333  0.      0.      0.    ]
 [ 0.3333  0.3333  0.      0.3333  0.      0.    ] 
 [ 0.3333  0.3333  0.      0.      0.3333  0.    ]
 [ 0.3333  0.3333  0.      0.      0.      0.3333]
 [ 0.3333  0.      0.3333  0.3333  0.      0.    ]
 [ 0.3333  0.      0.3333  0.      0.3333  0.    ]
 [ 0.3333  0.      0.3333  0.      0.      0.3333]
 [ 0.3333  0.      0.      0.3333  0.3333  0.    ]
 [ 0.3333  0.      0.      0.3333  0.      0.3333]
 [ 0.3333  0.      0.      0.      0.3333  0.3333]
 [ 0.      0.3333  0.3333  0.3333  0.      0.    ]
 [ 0.      0.3333  0.3333  0.      0.3333  0.    ]
 [ 0.      0.3333  0.3333  0.      0.      0.3333]
 [ 0.      0.3333  0.      0.3333  0.3333  0.    ]
 [ 0.      0.3333  0.      0.3333  0.      0.3333]
 [ 0.      0.3333  0.      0.      0.3333  0.3333]
 [ 0.      0.      0.3333  0.3333  0.3333  0.    ]
 [ 0.      0.      0.3333  0.3333  0.      0.3333]
 [ 0.      0.      0.3333  0.      0.3333  0.3333]
 [ 0.      0.      0.      0.3333  0.3333  0.3333]]
15.1 µs ± 74.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)