我目前正在使用NumPy来完成以下任务:我有一个大的值网格,我需要在每个点上取一个多项式样本。多项式的概率向量会随着网格位置的不同而变化,所以NumPy多项式函数对我来说不太适用,因为它的所有绘制都来自同一个分布。对每个站点进行迭代似乎效率极低,我想知道是否有一种方法可以在NumPy中高效地完成这项工作。如果我使用Theano(参见this answer),这样的事情似乎是可能的(而且很快),但这需要大量重写,这是我理想中希望避免的。多项式抽样能有效地在基元中进行矢量化吗?在
编辑:
修改Warren的代码以允许不同站点的不同计数是很容易的,因为我发现我需要做的就是传入完整的count
数组并删除第一个like,如下所示:
import numpy as np
def multinomial_rvs(count, p):
"""
Sample from the multinomial distribution with multiple p vectors.
* count must be an (n-1)-dimensional numpy array.
* p must an n-dimensional numpy array, n >= 1. The last axis of p
holds the sequence of probabilities for a multinomial distribution.
The return value has the same shape as p.
"""
out = np.zeros(p.shape, dtype=int)
ps = p.cumsum(axis=-1)
# Conditional probabilities
with np.errstate(divide='ignore', invalid='ignore'):
condp = p / ps
condp[np.isnan(condp)] = 0.0
for i in range(p.shape[-1]-1, 0, -1):
binsample = np.random.binomial(count, condp[..., i])
out[..., i] = binsample
count -= binsample
out[..., 0] = count
return out
可能的解决方案
原则上,您可以使用
numba
,因为multinomial
分布是受支持的。在Numba允许您简单地用
numba.njit
装饰器装饰numpy(更重要的是标准Python函数)来显著提高性能。在Check their documentation以更详细地查看此方法。尤其是
2.7.4
,因为它是关于支持np.random
(也支持多项式分布)。在下行:当前不支持
size
参数。您可以在嵌套循环中多次调用np.random.multinomial
,如果用numba.njit
修饰,它应该会更快。在最后但并非最不重要的一点:您可以使用
numba.prange
和parallel
参数将外部循环并行化到前面提到的decorator。在性能试验
第一次试验:
测试规范:
结果:
带类型签名的未调用numba
^{pr2}$一点都不麻木
可以看出,
numba
在这种情况下没有任何帮助(实际上它会降低性能)。对于不同大小的输入阵列,结果是一致的。在第二次试验
测试代码:
结果:
无类型签名的并行numba:
一点都不麻木
部分结论
正如max9111在评论中正确指出的那样,我过早地得出结论。似乎并行化(如果可能的话)对您的情况是最大的帮助,而
numba
(至少在这个仍然简单且不太全面的测试中)并没有带来很大的改进。在总之,您应该检查一下您的确切情况,根据经验,您使用的Python代码越多,使用
numba
可能会得到更好的结果。如果它主要是基于numpy
的,那么你不会看到任何好处(如果有的话)。在这里有一个方法你可以做到。它不是完全矢量化的,但是Python循环在
p
值之上。如果你的p
向量的长度不是太大,这可能对你来说足够快了。在多项式分布是通过重复调用
np.random.binomial
来实现的,它实现了参数的广播。在下面是一个例子,其中“网格”具有形状(2,3),多项式分布是四维的(即每个
^{pr2}$p
向量的长度为4)。在在一篇评论中,你说“p向量的形式是:p=[p_s,(1-p_s)/4,(1-p_s)/4,(1-p_s)/4,(1-p_s)/4],每个站点的p_都不同。”下面是如何使用上面的函数,给定一个包含
p_s
值的数组。在首先为示例创建一些数据:
根据公式
p = [p_s, (1-p_s)/4, (1-p_s)/4, (1-p_s)/4, (1-p_s)/4]
创建包含多项式概率的数组p
:现在执行与之前相同的操作以生成样本(将值1000更改为适合您的问题的任何值):
相关问题 更多 >
编程相关推荐