scipy.stats.sampling.

DiscreteAliasUrn#

scipy.stats.sampling.DiscreteAliasUrn(dist, *, domain=None, urn_factor=1, random_state=None)#

离散别名瓮法。

此方法用于针对具有有限域的单变量离散分布进行抽样。它使用大小为 \(N\) 的概率向量或具有有限支持的概率质量函数从分布中生成随机数。

参数:
distarray_like 或对象,可选

分布的概率向量 (PV)。如果没有 PV,则需要带有 pmf 方法的类的实例。PMF 的签名应为:def pmf(self, k: int) -> float”。换言之,它应接受 Python 整数并返回 Python 浮点数。

domainint,可选

PMF 的支持。如果无概率向量 (pv),则必须给出有限的域。即,PMF 必须具有有限的支持。默认值为 None。当为 None

  • 如果分发对象 dist 提供了 support 方法,则使用该方法设置分发区域。

  • 否则,假设支持为 (0, len(pv))。当此参数与概率向量组合传递时,domain[0] 用于将分布从 (0, len(pv)) 重新定位到 (domain[0], domain[0]+len(pv)),而 domain[1] 被忽略。请参阅注释和教程以获得更详细的说明。

urn_factorfloat,可选

相对于概率向量大小的 urn 表大小。它不能小于 1。较大的表格会导致更快的生成时间,但需要更昂贵的设置。默认值为 1。

random_state{None、int、numpy.random.Generator}

用于生成均匀随机数流的 NumPy 随机数生成器或底层 NumPy 随机数生成器的种子。如果 random_state 为 None(或 np.random),则使用 numpy.random.RandomState 单例。如果 random_state 为 int,则使用新的 RandomState 实例,并使用 random_state 播种。如果 random_state 已是 GeneratorRandomState 实例,则使用该实例。

注释

在以下情况下,此方法有效:有有限概率向量可用,或有分布的 PMF 可用。只在有 PMF 可用时,必须给定 PMF 的有限支持(区域)。建议先在支持中的每个点处评估 PMF 来获取概率向量,然后再使用它。

如果给定了概率向量,则概率向量一定是没有任何 infnan 值的非负浮点数一维数组。而且,至少必须有一个非零条目,否则将引发异常。

默认情况下,从 0 开始对概率向量编制索引。但是,可以通过传递 domain 参数来更改此项。当 domain 与 PV 一起给出时,就会将分布从 (0, len(pv)) 重新定位到 (domain[0], domain[0] + len(pv))。在这种情况下将忽略 domain[1]

可以增加参数 urn_factor,以加快生成速度,但会增加设置时间。此方法使用表格进行随机变量生成。 urn_factor 控制此表格相对于概率向量大小(或在不可用 PV 时支撑的宽度)的大小。由于此表格是在设置期间计算的,因此增加此参数会线性增加设置所需的时间。建议将此参数保持在 2 以下。

参考文献

[1]

UNU.RAN 参考手册,第 5.8.2 节,“DAU -(离散)别名壶方法” http://statmath.wu.ac.at/software/unuran/doc/unuran.html#DAU

[2]

A.J. Walker(1977)。一种生成具有通用分布的离散随机变量的高效方法,ACM Trans.数学软件 3,第 253-256 页。

例子

>>> from scipy.stats.sampling import DiscreteAliasUrn
>>> import numpy as np

要使用概率向量创建随机数生成器,请使用

>>> pv = [0.1, 0.3, 0.6]
>>> urng = np.random.default_rng()
>>> rng = DiscreteAliasUrn(pv, random_state=urng)

RNG 已设置。现在,我们可以使用 rvs 方法从分布中生成样本

>>> rvs = rng.rvs(size=1000)

要验证随机变量是否遵循给定的分布,我们可以使用卡方检验(作为拟合优度的衡量标准)

>>> from scipy.stats import chisquare
>>> _, freqs = np.unique(rvs, return_counts=True)
>>> freqs = freqs / np.sum(freqs)
>>> freqs
array([0.092, 0.292, 0.616])
>>> chisquare(freqs, pv).pvalue
0.9993602047563164

由于 p 值非常高,我们无法拒绝观测频率与预期频率相同的原假设。因此,我们可以安全地假设变量已从给定的分布中生成。请注意,这仅表示算法的正确性,并不表示样本的质量。

如果不可用 PV,也可以传递具有 PMF 方法和有限域的类的实例。

>>> urng = np.random.default_rng()
>>> class Binomial:
...     def __init__(self, n, p):
...         self.n = n
...         self.p = p
...     def pmf(self, x):
...         # note that the pmf doesn't need to be normalized.
...         return self.p**x * (1-self.p)**(self.n-x)
...     def support(self):
...         return (0, self.n)
...
>>> n, p = 10, 0.2
>>> dist = Binomial(n, p)
>>> rng = DiscreteAliasUrn(dist, random_state=urng)

现在,我们可以通过使用 rvs 方法从分布中进行采样,还可以测量样本的拟合优度

>>> rvs = rng.rvs(1000)
>>> _, freqs = np.unique(rvs, return_counts=True)
>>> freqs = freqs / np.sum(freqs)
>>> obs_freqs = np.zeros(11)  # some frequencies may be zero.
>>> obs_freqs[:freqs.size] = freqs
>>> pv = [dist.pmf(i) for i in range(0, 11)]
>>> pv = np.asarray(pv) / np.sum(pv)
>>> chisquare(obs_freqs, pv).pvalue
0.9999999999999999

为了检查样本是否从正确的分布中抽取,我们可以查看样本的直方图

>>> import matplotlib.pyplot as plt
>>> rvs = rng.rvs(1000)
>>> fig = plt.figure()
>>> ax = fig.add_subplot(111)
>>> x = np.arange(0, n+1)
>>> fx = dist.pmf(x)
>>> fx = fx / fx.sum()
>>> ax.plot(x, fx, 'bo', label='true distribution')
>>> ax.vlines(x, 0, fx, lw=2)
>>> ax.hist(rvs, bins=np.r_[x, n+1]-0.5, density=True, alpha=0.5,
...         color='r', label='samples')
>>> ax.set_xlabel('x')
>>> ax.set_ylabel('PMF(x)')
>>> ax.set_title('Discrete Alias Urn Samples')
>>> plt.legend()
>>> plt.show()
../../_images/scipy-stats-sampling-DiscreteAliasUrn-1_00_00.png

要设置 urn_factor,请使用

>>> rng = DiscreteAliasUrn(pv, urn_factor=2, random_state=urng)

这将使用一张表(大小是概率向量的两倍)从分布中生成随机变量。

方法

rvs([size, random_state])

从分布中进行采样。

set_random_state([random_state])

设置基础均匀随机数生成器。