# Lib/random.py defrandom(self): """Get the next random number in the range [0.0, 1.0).""" return (int.from_bytes(_urandom(7), 'big') >> 3) * RECIP_BPF
defgauss(self, mu, sigma): """Gaussian distribution. mu is the mean, and sigma is the standard deviation. This is slightly faster than the normalvariate() function. Not thread-safe without a lock around calls. """
# When x and y are two variables from [0, 1), uniformly # distributed, then # # cos(2*pi*x)*sqrt(-2*log(1-y)) # sin(2*pi*x)*sqrt(-2*log(1-y)) # # are two *independent* variables with normal distribution # (mu = 0, sigma = 1). # (Lambert Meertens) # (corrected version; bug discovered by Mike Miller, fixed by LM)
# Multithreading note: When two threads call this function # simultaneously, it is possible that they will receive the # same return value. The window is very small though. To # avoid this, you have to use a lock around all calls. (I # didn't want to slow this down in the serial case by using a # lock here.)
random = self.random z = self.gauss_next self.gauss_next = None if z isNone: x2pi = random() * TWOPI g2rad = _sqrt(-2.0 * _log(1.0 - random())) z = _cos(x2pi) * g2rad self.gauss_next = _sin(x2pi) * g2rad
return mu + z*sigma
下面是我自己基于numpy实现的向量化版本:
1 2 3 4 5 6
defBoxMuller(mu=0, sigma=1, iter=1000): rand1 = np.random.random(size=(iter,)) rand2 = np.random.random(size=(iter,)) x = np.sqrt(-2*np.log(rand1)) * np.sin(2*np.pi*rand2) # y = np.sqrt(-2*np.log(rand1)) * np.sin(2*np.pi*rand2) return x
def_reject_unit_round(iter=1000): count = 0 x_samples = [None] * iter y_samples = [None] * iter r_samples = [None] * iter
while count < iter: flag = True while flag: x = random()*2-1 y = random()*2-1 r = x ** 2 + y ** 2 if0 < r <= 1: flag = False x_samples[count] = x y_samples[count] = y r_samples[count] = r count += 1 return np.array(x_samples), np.array(y_samples), np.array(r_samples)
defMarsagliaPolar(mu=0, sigma=1, iter=1000): x, y, r = _reject_unit_round(iter) return x * np.sqrt(-2 * np.log(r) / r)
全称是Markov Chain Monte Carlo,即马尔科夫链蒙特卡洛方法。蒙特卡洛方法是一系列随机方法,所谓蒙特卡洛模拟(Monte Carlo simulations),是指一种通过重复生成随机数来估计固定参数的方法。通过生成随机数并对其进行一些计算,蒙特卡洛模拟能够为某一无法直接计算(或者直接计算成本过于高昂)的参数提供近似值。
import numpy as np import scipy.special as ss import matplotlib.pyplot as plt
defbeta_s(x, a, b): return x**(a-1)*(1-x)**(b-1) defbeta(x, a, b): return beta_s(x, a, b)/ss.beta(a, b)
defplot_mcmc(a, b): cur = np.random.rand() states = [cur] for i in range(10**5): next, u = np.random.rand(2) if u < np.min((beta_s(next, a, b)/beta_s(cur, a, b), 1)): states.append(next) cur = next x = np.arange(0, 1, .01) plt.figure(figsize=(10, 5)) plt.plot(x, beta(x, a, b), lw=2, label='real dist: a={}, b={}'.format(a, b)) plt.hist(states[-1000:], 25, normed=True, label='simu mcmc: a={}, b={}'.format(a, b)) plt.show()
if __name__ == '__main__': plot_mcmc(0.1, 0.1) plot_mcmc(1, 1) plot_mcmc(2, 3)