scipy.stats.sampling.

DiscreteAliasUrn#

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

離散別名罐子方法。

此方法用於從具有有限域的單變數離散分佈中取樣。它使用大小為 \(N\) 的機率向量或具有有限支持的機率質量函數,從分佈中生成隨機數。

參數:
distarray_like 或 object,選填

分佈的機率向量 (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] 會被忽略。有關更詳細的說明,請參閱「Notes」和教學。

urn_factorfloat,選填

罐子表的大小相對於機率向量的大小。它不能小於 1。較大的表會產生更快的生成時間,但需要更昂貴的設定。預設值為 1。

random_state{None, int, numpy.random.Generator,

NumPy 隨機數生成器或用於生成均勻隨機數流的底層 NumPy 隨機數生成器的種子。如果 random_state 為 None (或 np.random),則使用 numpy.random.RandomState 單例。如果 random_state 是一個整數,則會使用一個新的 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 - (Discrete) Alias-Urn method」,http://statmath.wu.ac.at/software/unuran/doc/unuran.html#DAU

[2]

A.J. Walker (1977)。用於生成具有一般分佈的離散隨機變數的有效方法,ACM Trans. Math. Software 3, pp. 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])

設定底層的均勻隨機數生成器。