我有一些编程代码,用MCMC(Metropolis Hastings)对后验分布进行抽样。我使用scipy生成随机样本:
import numpy as np
from scipy import stats
def get_samples(n):
"""
Generate and return a randomly sampled posterior.
For simplicity, Prior is fixed as Beta(a=2,b=5), Likelihood is fixed as Normal(0,2)
:type n: int
:param n: number of iterations
:rtype: numpy.ndarray
"""
x_t = stats.uniform(0,1).rvs() # initial value
posterior = np.zeros((n,))
for t in range(n):
x_prime = stats.norm(loc=x_t).rvs() # candidate
p1 = stats.beta(a=2,b=5).pdf(x_prime)*stats.norm(loc=0,scale=2).pdf(x_prime) # prior * likelihood
p2 = stats.beta(a=2,b=5).pdf(x_t)*stats.norm(loc=0,scale=2).pdf(x_t) # prior * likelihood
alpha = p1/p2 # ratio
u = stats.uniform(0,1).rvs() # random uniform
if u <= alpha:
x_t = x_prime # accept
posterior[t] = x_t
elif u > alpha:
x_t = x_t # reject
posterior = posterior[np.where(posterior > 0)] # get rid of initial zeros that don't contribute to distribution
return posterior
通常情况下,我尽量避免在Python中使用显式for循环 - 我会尝试使用纯numpy生成所有内容。然而,在这种算法的情况下,无法避免使用if语句的for循环。因此,代码速度相当慢。当我分析我的代码时,它大部分时间都花在for循环内(显然),更具体地说,最慢的部分是生成随机数;
stats.beta().pdf()
和stats.norm().pdf()
。有时我会使用numba来加速矩阵运算。虽然numba与某些numpy操作兼容,但生成随机数不属于其中之一。Numba有一个cuda rng,但这仅限于正态和均匀分布。
我的问题是,是否有一种方式可以使用各种分布的随机抽样来显着加速上述代码,并且与numba兼容?
我们不必局限于numba,但它是我知道的唯一易于使用的优化器。更普遍地说,我正在寻找加速Python中各种分布(beta、gamma、泊松)的随机抽样在for循环中的方法。
stats.beta().pdf()
和stats.norm().pdf()
不会生成随机数。它们正在评估概率分布的密度。 - jwalton