scipy.stats.sampling.

DiscreteGuideTable#

class scipy.stats.sampling.DiscreteGuideTable(dist, *, domain=None, guide_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] 會被忽略。有關更詳細的說明,請參閱註解和教學。

guide_factor: int,選用

導引表大小相對於 PV 長度。較大的導引表會導致更快的產生時間,但需要更昂貴的設置。不建議使用大於 3 的大小。如果相對大小設定為 0,則使用循序搜尋。預設值為 1。

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

用於產生均勻隨機數串流的底層 NumPy 隨機數產生器或種子。如果 random_state 為 None(或 np.random),則使用 numpy.random.RandomState 單例。如果 random_state 為 int,則會使用新的 RandomState 實例,並以 random_state 作為種子。如果 random_state 已經是 GeneratorRandomState 實例,則使用該實例。

註解

當有限機率向量可用或分佈的 PMF 可用時,此方法有效。如果僅 PMF 可用,則還必須給定 PMF 的有限支持域。建議先通過評估支持域中每個點的 PMF 來獲得機率向量,然後使用它。

DGT 從任意但有限的機率向量中取樣。隨機數是通過反演方法產生的,即

  1. 產生一個隨機數 U ~ U(0,1)。

  2. 找到最小整數 I,使得 F(I) = P(X<=I) >= U。

步驟 (2) 是關鍵步驟。使用循序搜尋需要 O(E(X)) 次比較,其中 E(X) 是分佈的期望值。然而,索引搜尋使用導引表跳到某些 I’ <= I 附近的 I,以便在恆定時間內找到 X。實際上,當導引表的大小與機率向量相同時(這是預設值),預期的比較次數減少到 2。對於較大的導引表,這個數字會變小(但總是大於 1),對於較小的表,它會變大。對於表大小為 1 的極限情況,演算法只進行循序搜尋。

另一方面,導引表的設置時間為 O(N),其中 N 表示機率向量的長度(對於大小為 1,不需要預處理)。此外,對於非常大的導引表,記憶體效應甚至可能會降低演算法的速度。因此,我們不建議使用比給定機率向量大三倍以上的導引表。如果只需要產生少量隨機數,則(小得多)的表大小會更好。導引表大小相對於給定機率向量長度的大小可以通過 guide_factor 參數設定。

如果給定機率向量,它必須是沒有任何 infnan 值的非負浮點數的一維陣列。此外,必須至少有一個非零條目,否則會引發異常。

預設情況下,機率向量的索引從 0 開始。但是,可以通過傳遞 domain 參數來更改此設定。當 domain 與 PV 組合給定時,它的作用是將分佈從 (0, len(pv)) 重新定位到 (domain[0], domain[0] + len(pv))domain[1] 在這種情況下會被忽略。

參考文獻

[1]

UNU.RAN 參考手冊,第 5.8.4 節,“DGT -(離散)導引表方法(索引搜尋)” https://statmath.wu.ac.at/unuran/doc/unuran.html#DGT

[2]

H.C. Chen 和 Y. Asau (1974)。On generating random variates from an empirical distribution, AIIE Trans. 6, pp. 163-166.

範例

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

要使用機率向量建立隨機數產生器,請使用

>>> pv = [0.1, 0.3, 0.6]
>>> urng = np.random.default_rng()
>>> rng = DiscreteGuideTable(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.355, 0.553])
>>> chisquare(freqs, pv).pvalue
0.9987382966178464

由於 p 值非常高,我們無法拒絕虛無假設,即觀察到的頻率與預期頻率相同。因此,我們可以安全地假設變數是從給定的分佈產生的。請注意,這僅給出了演算法的正確性,而不是樣本的品質。

如果 PV 不可用,也可以傳遞具有 PMF 方法和有限域的類別實例。

>>> urng = np.random.default_rng()
>>> from scipy.stats import binom
>>> n, p = 10, 0.2
>>> dist = binom(n, p)
>>> rng = DiscreteGuideTable(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.9999999999999989

為了檢查樣本是否從正確的分佈中抽取,我們可以將樣本的直方圖視覺化

>>> 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 Guide Table Samples')
>>> plt.legend()
>>> plt.show()
../../_images/scipy-stats-sampling-DiscreteGuideTable-1_00_00.png

要設定導引表的大小,請使用 guide_factor 關鍵字引數。這會設定導引表大小相對於機率向量的大小

>>> rng = DiscreteGuideTable(pv, guide_factor=1, random_state=urng)

要計算二項分佈的 PPF,其中 \(n=4\)\(p=0.1\):我們可以按如下方式設定導引表

>>> n, p = 4, 0.1
>>> dist = binom(n, p)
>>> rng = DiscreteGuideTable(dist, random_state=42)
>>> rng.ppf(0.5)
0.0

方法

ppf(u)

給定分佈的 PPF。

rvs([size, random_state])

從分佈中取樣。

set_random_state([random_state])

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