将分发参数作为数组传递

时间:2017-03-15 16:25:42

标签: python-3.x numpy scipy

我需要一次生成许多样本,它们具有相同的分布类型,但参数不同。我尝试了以下代码:

a = np.array([1,2,3])
size = 5
sample = sps.norm.rvs(size=size, loc=a)

但是我收到以下错误:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/<me>/.pyenv/versions/study/lib/python3.5/site-packages/scipy/stats/_distn_infrastructure.py", line 933, in rvs
args, loc, scale, size = self._parse_args_rvs(*args, **kwds)
File "<string>", line 6, in _parse_args_rvs
File "/Users/<me>/.pyenv/versions/study/lib/python3.5/site-packages/scipy/stats/_distn_infrastructure.py", line 847, in _argcheck_rvs
raise ValueError("size does not match the broadcast shape of "
ValueError: size does not match the broadcast shape of the parameters.

认为尺寸参数可能也是3号大小的ndy数组,我做了以下几点:

size = np.array([5,5,5])

只有同样的例外才会受到欢迎:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/<me>/.pyenv/versions/study/lib/python3.5/site-packages/scipy/stats/_distn_infrastructure.py", line 933, in rvs
args, loc, scale, size = self._parse_args_rvs(*args, **kwds)
File "<string>", line 6, in _parse_args_rvs
File "/Users/<me>/.pyenv/versions/study/lib/python3.5/site-packages/scipy/stats/_distn_infrastructure.py", line 847, in _argcheck_rvs
raise ValueError("size does not match the broadcast shape of "
ValueError: size does not match the broadcast shape of the parameters.

认为文档可能是答案,我做了help(sps.norm.rvs),看到以下内容:

arg1, arg2, arg3,... : array_like
    The shape parameter(s) for the distribution (see docstring of the
    instance object for more information).

我不太确定实例对象是什么,所以我提到了this问题,并在help(sps.norm)中输入,只是为了看到答案仍然未知:

rvs(self, *args, **kwds)
  Random variates of given type.

  Parameters
  ----------
  arg1, arg2, arg3,... : array_like
      The shape parameter(s) for the distribution (see docstring of the
      instance object for more information).

我在哪里可以找到所需的文档字符串,更重要的是,如何使用不同的参数一次生成多个样本?

1 个答案:

答案 0 :(得分:2)

rvs方法广播,但size参数必须是结果的最终大小。如果您有3个位置值,并且想要为每个位置值绘制5个样本,则可以使用size=(5, 3)

In [118]: from scipy.stats import norm

In [119]: a = np.array([1, 2, 4])

In [120]: norm.rvs(loc=a, scale=0.05, size=(5, 3))
Out[120]: 
array([[ 1.01730871,  2.01713648,  3.96844145],
       [ 0.96102855,  2.03925685,  3.93189097],
       [ 0.98847545,  1.98229486,  4.00753205],
       [ 0.99843892,  1.95899283,  3.98745337],
       [ 1.01457605,  1.97508746,  4.07114077]])

如果使用此技术,请确保至少有scipy版本0.18.0。以前的版本在rvs方法的广播行为中有a bug

这是一个更复杂的例子:

假设您有3个位置值和2个比例值,并且对于每对, 你想画5个样本。此外,您希望结果的形状 是(3,2,5)。

以下是位置和比例数组:

In [136]: a = np.array([1, 2, 4])

In [137]: s = np.array([0.05, 0.001])

我们会在size=(3, 2, 5)的调用中使用rvs(),因此我们必须这样做 locscale参数的形状与numpy一致 广播规则。 loc形状必须为(3, 1, 1), 并且scale形状必须为(1, 2, 1)。 (形状(2, 1) 也是一致的。)将这些微不足道的维度添加到a, 我们可以使用Nonea[:,None,None]进行索引,或者我们可以使用reshape 方法,a.reshape(-1, 1, 1)。我们可以为s做同样的事情 我们将它用作scale参数。

所以对rvs()的调用是

In [138]: samples = norm.rvs(loc=a[:,None,None], scale=s[None,:,None], size=(3, 2, 5))

In [139]: samples.shape
Out[139]: (3, 2, 5)

In [140]: samples[0, 0]  # loc=1, scale=0.05
Out[140]: array([ 1.0343322 ,  1.06019143,  0.95058855,  1.04184266,  1.00383671])

In [141]: samples[2, 1]  # loc=4, scale=0.001
Out[141]: array([ 4.00106506,  4.00066642,  3.99801552,  3.99829284,  4.00114079])