美文网首页
蒙特卡洛理解与python实现1-如何生成随机变量

蒙特卡洛理解与python实现1-如何生成随机变量

作者: _龙雀 | 来源:发表于2020-03-26 14:46 被阅读0次

蒙特卡洛系列算法需要进行随机变量的采样,先理解如何生成(仿真)随机变量(这里只讨论连续型随机变量的生成)。

逆变换法(Inverse Transform Method)

  • 原理:如果我们有一个随机变量U符合[0,1]均匀分布,并且X=F^{-1}(U),那么X就是一个分布函数(CDF)为F的随机变量。也就是说如果我们需要生成符合标分布F的随机变量X,先用均匀分布生成随机变量U,将其输入F^{-1},得到的函数输出结果就是我们需要的X。

一句话总结:严格单调递增(保证有逆函数)的累积分布函数服从均匀分布

image.png
  • 证明:见参考文献

  • 算法


    image.png
  • 算法实践:采样符合logistic分布的随机变量X

  1. logistic分布的CDF是F(x) = \frac{e^x}{1+e^x}, x \in R
    求其逆函数得F^{-1}(x) = log\frac{x}{1+x}
  2. 给定u \sim unif(0,1),则X = F^{-1}(u) = log\frac{u}{1+u} \sim logistic
#下面所有代码均引用这两个包
import numpy as np
import matplotlib.pyplot as plt  

def inverse_transform():
    results = []
    N = 1000
    for i in range(N):
        u = np.random.uniform(0,1)
        x = np.log(u / (1-u))
        results.append(x)
    return results

results_inv = inverse_transform()
plt.hist(results_inv,bins=100,color='green')
plt.show()
image.png
  1. 理论验证

P(log(\frac{u}{1-u})\leq x) = P(\frac{u}{1-u} \leq e^x) = P(u \leq \frac{e^x}{1+e^x} ) = F_{U}( \frac{e^x}{1+e^x} ) =\frac{e^x}{1+e^x} = F(X)

其中F_U(u)是指u的均匀分布的CDF,F(u) = \frac{u-a}{b-1} , u = \frac{e^x}{1+e^x}\in (0,1)

对于另外一些随机变量,比如正态分布,F^{-1}不可求,需要用其他方法,
主要有构成法、Box-Muller法、接受-拒绝法

Box Muller 方法 -仅针对正态分布

  • 原理:如题意描述,这个联合随机分布(X,Y)是一个二元正态分布,其边缘分布 X,Y是是两个独立的标准正态分布N(0,1)
    image.png
  • 证明:略
  • 算法:python中默认的正态分布生成方法即是这个


    image.png

其中包含了 --》如何利用逆变换法生成符合指数分布的随机变量T:

假设 T\sim Expo(\lambda) 则有F(t) = 1-e^{-\lambda t}, T = F^{-1}(u) =-\frac{1}{\lambda} *ln(1-u) ,由于u\sim unif(0,1), 则1-u \sim unif(0,1),所以算法中对于T\sim Expo(1)直接生成-lnU

-算法实践:利用box-muller算法生成标准正态分布

# Box-Muller  
# Box-Muller  
def box_muller():
    results = []
    N = 1000
    for i in range(N):
        u = np.random.uniform(0, 1, 2) #同时生成2个符合【0,1】均匀分布的随机变量【u1,u2】
        x = np.cos(2*np.pi*u[0])*np.sqrt(-2*np.log(u[1]))
        y = np.sin(2*np.pi*u[0])*np.sqrt(-2*np.log(u[1]))
        results.append(x) #采样x、y中任意一个即可
    return results

results_boxmuller = box_muller()
plt.hist(results_boxmuller,bins=100,color='green')
plt.show()
image.png

接受拒绝法(Acceptance-Rejection Algorithm)

  • 原理:如果直接生成目标p分布不容易生成,可以先生成容易得到的q分布,再利用接受拒绝法得到p。
  • 证明:见参考文献
  • 算法:


    image.png
  • 算法实践:利用接受拒绝法从指数分布Expo(1)中生成标准正态分布N(0,1)

求出c:

  1. Expo(1)的概率密度函数(PDF)为q(x)=e^{-x},x\geq0
  2. 假设Z \sim N(0,1),目标分布为p(x)=|Z|\sim \frac{2}{\sqrt{2\pi}} e^{-0.5x^2},x\geq 0 (因为指数分布的定义中x\geq0,所以先生成标准正态分布的绝对值)
  3. \sup_{x} \frac{p(x)}{q(x)} = \sup_{x} \sqrt{\frac{2}{\pi}} e^{x-0.5x^2} = \sqrt{\frac{2e}{\pi}}
  4. c = \sqrt{\frac{2e}{\pi}}
    其中sup是上确界的意思,sup和max都是定义在实数集的函数,不同点在于sup是对这个集合取上确界,max是取最大值,最大值存在时,最大值就是上确界

算法过程:

  1. 使用逆变换法生成指数分布 y\sim q\sim expo(1)
  2. 生成均匀分布u\sim unif(0,1)
  3. 代入u\leq \frac{p(y)}{cq(y)}u\leq e^{-0.5(y-1)^2}
    if u\leq e^{-0.5(y-1)^2}, x = y
  4. 得到 x\sim |Z|之后,令
    \begin{equation} Z= \begin{cases} x& p=0.5 \\ -x& p=0.5 \end{cases} \end{equation}Z\sim N(0,1)
def acc_rej():
    results = []
    N = 10000
    for i in range(N):
        #先生成符号q分布即指数分布的随机变量y
        #u = np.random.uniform(0,1)
        #y = -np.log(1-u) 利用逆变换法生成指数分布
        y = np.random.exponential(1) #直接利用numpy中的函数生成指数分布
        u = np.random.uniform(0,1)
        if u <= np.exp(-0.5*(y-1)**2):
            x = y
            z = np.random.choice([x,-x],size = 1,p=[0.5,0.5])
            results.append(z[0]) #z为numpy数组 取出其中的value
    return results
     
results_accrej = acc_rej()
plt.hist(results_accrej, bins=100, color='green')
plt.show()
  • 算法实践2:利用接受拒绝法从q:Unif(0,1)中生成p:Beta(2,2)
  1. Beta分布的PDF: p(x,\alpha,\beta) = \frac{1}{B(\alpha,\beta)}x^{\alpha-1}(1-x)^{\beta-1}
    其中的B为beta函数\mathrm{B}(a, b)=\int_{0}^{1} x^{a-1}(1-x)^{b-1} \mathrm{d} x
  2. 代入得p(x,2,2) = -6x^2+6x, 均匀分布q(x)=1,则c \geq \sup_{x} \frac{p(x)}{q(x)} = \sup_{x}( -6x^2+6x) = 1.5取c=1.5
  3. 将c代入,得u\leq \frac{p(y)}{cq(y)} = -4y^2+4y
#用均匀分布生成beta(2,2)分布x
def acc_rej():
    results = []
    N = 10000
    for i in range(N):
        y = np.random.uniform(0,1) #q分布
        u = np.random.uniform(0,1)
        if u <= (-4)*y**2+4*y:
            x = y
            results.append(x)
    return results
     
results_accrej = acc_rej()
plt.hist(results_accrej, bins=100, color='green')
plt.show()
  • 接受拒绝法中隐含的tradeoff
    如果我们选择的分布q越接近p,则c越接近于1,因此生成的随机变量y越容易被接收,那么acc-rej算法所需要的迭代次数将会减少,从而导致计算量减小。
    但是,如果q足够接近p,那么采样分布q也变得困难(之所以使用接收拒绝法正是因为难以采样分布p)因此如何平衡容易采样的分布q和足够小的c是关键。一方面,我们想要c足够小,接近1以减小计算量,另一方面我们又希望q容易采样。

逆变换法 vs 接受拒绝法

  • 逆变换法是在CDF上操作,需要CDF逆函数可求
  • 接受拒绝法是在PDF上操作
    • 使用该方法,对于要生成的目标p分布不需要进行归一化,算法本身是自我归一化的(self-normalizing)
    • c\geq 1

参考文献

  1. http://www.columbia.edu/~mh2078/MonteCarlo.html 中的第一讲Generating Random Variables and StochasticProcesses。里面的课件和notes给了很多详细的证明过程,以及其他的内容如何生成多维的随机变量、离散的随机变量等。
  2. https://cosx.org/2015/06/generating-normal-distr-variates/ 作者总结了生成正态分布的各种方法,包含相关证明。

相关文章

网友评论

      本文标题:蒙特卡洛理解与python实现1-如何生成随机变量

      本文链接:https://www.haomeiwen.com/subject/wgyquhtx.html