如上图所示,计算区间[a  b]上f(x)的积分即求曲线与X轴围成红色区域的面积。下面使用蒙特卡洛法计算区间[2  3]上的定积分:∫(x2+4*x*sin(x))dx

 # -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt def f(x):
return x**2 + 4*x*np.sin(x) def intf(x):
return x**3/3.0+4.0*np.sin(x) - 4.0*x*np.cos(x) a = 2;
b = 3; # use N draws
N= 10000 X = np.random.uniform(low=a, high=b, size=N) # N values uniformly drawn from a to b
Y =f(X) # CALCULATE THE f(x) # 蒙特卡洛法计算定积分:面积=宽度*平均高度
Imc= (b-a) * np.sum(Y)/ N; exactval=intf(b)-intf(a) print "Monte Carlo estimation=",Imc, "Exact number=", intf(b)-intf(a) # --How does the accuracy depends on the number of points(samples)? Lets try the same 1-D integral
# The Monte Carlo methods yield approximate answers whose accuracy depends on the number of draws.
Imc=np.zeros(1000)
Na = np.linspace(0,1000,1000) exactval= intf(b)-intf(a) for N in np.arange(0,1000):
X = np.random.uniform(low=a, high=b, size=N) # N values uniformly drawn from a to b
Y =f(X) # CALCULATE THE f(x)
Imc[N]= (b-a) * np.sum(Y)/ N; plt.plot(Na[10:],np.sqrt((Imc[10:]-exactval)**2), alpha=0.7)
plt.plot(Na[10:], 1/np.sqrt(Na[10:]), 'r')
plt.xlabel("N")
plt.ylabel("sqrt((Imc-ExactValue)$^2$)")
plt.show()

>>>

Monte Carlo estimation= 11.8181144118    Exact number= 11.8113589251

从上图可以看出,随着采样点数的增加,计算误差逐渐减小。想要提高模拟结果的精确度有两个途径:其一是增加试验次数N;其二是降低方差σ2. 增加试验次数势必使解题所用计算机的总时间增加,要想以此来达到提高精度之目的显然是不合适的。下面来介绍重要抽样法来减小方差,提高积分计算的精度。

重要性抽样法的特点在于,它不是从给定的过程的概率分布抽样,而是从修改的概率分布抽样,使对模拟结果有重要作用的事件更多出现,从而提高抽样效率,减少花费在对模拟结果无关紧要的事件上的计算时间。比如在区间[a  b]上求g(x)的积分,若采用均匀抽样,在函数值g(x)比较小的区间内产生的抽样点跟函数值较大处区间内产生的抽样点的数目接近,显然抽样效率不高,可以将抽样概率密度函数改为f(x),使f(x)与g(x)的形状相近,就可以保证对积分计算贡献较大的抽样值出现的机会大于贡献小的抽样值,即可以将积分运算改写为:

x是按照概率密度f(x)抽样获得的随机变量,显然在区间[a  b]内应该有:

因此,可容易将积分值I看成是随机变量 Y = g(x)/f(x)的期望,式子中xi是服从概率密度f(x)的采样点

下面的例子采用一个正态分布函数f(x)来近似g(x)=sin(x)*x,并依据正态分布选取采样值计算区间[0  pi]上的积分个∫g(x)dx

 # -*- coding: utf-8 -*-
# Example: Calculate ∫sin(x)xdx # The function has a shape that is similar to Gaussian and therefore
# we choose here a Gaussian as importance sampling distribution. from scipy import stats
from scipy.stats import norm
import numpy as np
import matplotlib.pyplot as plt mu = 2;
sig =.7; f = lambda x: np.sin(x)*x
infun = lambda x: np.sin(x)-x*np.cos(x)
p = lambda x: (1/np.sqrt(2*np.pi*sig**2))*np.exp(-(x-mu)**2/(2.0*sig**2))
normfun = lambda x: norm.cdf(x-mu, scale=sig) plt.figure(figsize=(18,8)) # set the figure size # range of integration
xmax =np.pi
xmin =0 # Number of draws
N =1000 # Just want to plot the function
x=np.linspace(xmin, xmax, 1000)
plt.subplot(1,2,1)
plt.plot(x, f(x), 'b', label=u'Original $x\sin(x)$')
plt.plot(x, p(x), 'r', label=u'Importance Sampling Function: Normal')
plt.xlabel('x')
plt.legend()
# =============================================
# EXACT SOLUTION
# =============================================
Iexact = infun(xmax)-infun(xmin)
print Iexact
# ============================================
# VANILLA MONTE CARLO
# ============================================
Ivmc = np.zeros(1000)
for k in np.arange(0,1000):
x = np.random.uniform(low=xmin, high=xmax, size=N)
Ivmc[k] = (xmax-xmin)*np.mean(f(x)) # ============================================
# IMPORTANCE SAMPLING
# ============================================
# CHOOSE Gaussian so it similar to the original functions # Importance sampling: choose the random points so that
# more points are chosen around the peak, less where the integrand is small.
Iis = np.zeros(1000)
for k in np.arange(0,1000):
# DRAW FROM THE GAUSSIAN: xis~N(mu,sig^2)
xis = mu + sig*np.random.randn(N,1);
xis = xis[ (xis<xmax) & (xis>xmin)] ; # normalization for gaussian from 0..pi
normal = normfun(np.pi)-normfun(0) # 注意:概率密度函数在采样区间[0 pi]上的积分需要等于1
Iis[k] =np.mean(f(xis)/p(xis))*normal # 因此,此处需要乘一个系数即p(x)在[0 pi]上的积分 plt.subplot(1,2,2)
plt.hist(Iis,30, histtype='step', label=u'Importance Sampling');
plt.hist(Ivmc, 30, color='r',histtype='step', label=u'Vanilla MC');
plt.vlines(np.pi, 0, 100, color='g', linestyle='dashed')
plt.legend()
plt.show()

从图中可以看出曲线sin(x)*x的形状和正态分布曲线的形状相近,因此在曲线峰值处的采样点数目会比曲线上位置低的地方要多。精确计算的结果为pi,从上面的右图中可以看出:两种方法均计算定积分1000次,靠近精确值pi=3.1415处的结果最多,离精确值越远数目越少,显然这符合常规。但是采用传统方法(红色直方图)计算出的积分值方的差明显比采用重要抽样法(蓝色直方图)要大。因此,采用重要抽样法计算可以降低方差,提高精度。另外需要注意的是:关于函数f(x)的选择会对计算结果的精度产生影响,当我们选择的函数f(x)与g(x)相差较大时,计算结果的方差也会加大。

参考:

http://iacs-courses.seas.harvard.edu/courses/am207/blog/lecture-3.html

蒙特卡洛法计算定积分—Importance Sampling的更多相关文章

  1. Not All Samples Are Created Equal: Deep Learning with Importance Sampling

    目录 概 主要内容 "代码" Katharopoulos A, Fleuret F. Not All Samples Are Created Equal: Deep Learnin ...

  2. Implemented the “Importance Sampling of Reflections from Hair Fibers”

      Just the indirect specular pass by importance sampling. With all layers. Manually traced by 3D Ham ...

  3. [Bayes] Hist & line: Reject Sampling and Importance Sampling

    吻合度蛮高,但不光滑. > L= > K=/ > x=runif(L) > *x*(-x)^/K)) > hist(x[ind],probability=T, + xla ...

  4. Importance sampling

    用蒙特卡洛求解积分时 (Monte Carlo 随机采样对目标积分函数做近似) importance sampling func p(x) p(x)值大的地方,Monte Carlo多采几次 值小的地 ...

  5. 转 如何理解 重要性采样(importance sampling)

    分类: 我叫学术帖2011-03-25 13:22 3232人阅读 评论(4) 收藏 举报 图形 重要性采样是非常有意 思的一个方法.我们首先需要明确,这个方法是基于采样的,也就是基于所谓的蒙特卡洛法 ...

  6. 小小知识点(二十)利用MATLAB计算定积分

    一重定积分 1. Z = trapz(X,Y,dim) 梯形数值积分,通过已知参数x,y按dim维使用梯形公式进行积分 %举例说明1 clc clear all % int(sin(x),0,pi) ...

  7. C++ 计算定积分、不定积分、蒙特卡洛积分法

    封装成了一个类,头文件和源文件如下: integral.h #pragma once //Microsoft Visual Studio 2015 Enterprise #include <io ...

  8. 随机模拟的基本思想和常用采样方法(sampling)

    转自:http://blog.csdn.net/xianlingmao/article/details/7768833 引入 我们会遇到很多问题无法用分析的方法来求得精确解,例如由于式子特别,真的解不 ...

  9. PRML读书会第十一章 Sampling Methods(MCMC, Markov Chain Monte Carlo,细致平稳条件,Metropolis-Hastings,Gibbs Sampling,Slice Sampling,Hamiltonian MCMC)

    主讲人 网络上的尼采 (新浪微博: @Nietzsche_复杂网络机器学习) 网络上的尼采(813394698) 9:05:00  今天的主要内容:Markov Chain Monte Carlo,M ...

随机推荐

  1. 关于wxwidgets图形界面的关闭窗口的按钮无效的解决办法

    这是使用wxsmith设计界面时的情况,如果用纯代码写的界面,关闭按钮就很奇怪地有效 道听途说,窗口的关闭是由一个方法控制着.大概是这样的: void PlainFrame::OnClose(wxCl ...

  2. WCF入门教程:WCF基础知识问与答(转)

    学习WCF已有近两年的时间,其间又翻译了Juval的大作<Programming WCF Services>,我仍然觉得WCF还有更多的内容值得探索与挖掘.学得越多,反而越发觉得自己所知太 ...

  3. notification 通知

    1. 定义一个方法 -(void) update{ } 2. 对象注册,并关连消息 [[NSNotificationCenter defaultCenter]addObserver:self sele ...

  4. 【python cookbook】【字符串与文本】8.编写多行模式的正则表达式

    问题:用正则表达式对一段文本块做匹配,但是希望在进行匹配时能够跨越多行 解决方案: 1.正则表达式添加对换行符的支持: 2.re.compile()函数一个有用的标记-re.DOTALL使得正则表达式 ...

  5. tomcat监控脚本

    工作所需,匆匆忙忙写了个监控tomcat的shell脚本,大概思路是这样的:先检测tomcat进程是否存在,如果不存在就启动,如果进程存在,检测页面返回码状态,如果是200就是正常,如果不是就重启. ...

  6. java网络编程之TCP通讯

    java中的网络编程之TCP协议的详细介绍,以及如何使用,同时我在下面举2例说明如何搭配IO流进行操作, /* *TCP *建立连接,形成传输数据的通道: *在连接中进行大数据量传输: *通过三次握手 ...

  7. Intellij IDEA

    http://1358440610-qq-com.iteye.com/blog/2102195

  8. PHP建站通过服务器架构及实战的方法

    PHP的环境搭建 PHP的帮助使用和配置文件 PHP的Hello World PHP的库函数调用 PHP的Web程序 PHP的函数和面向对象使用 PHP的数据库访问 Nginx安装和配置访问 Word ...

  9. run loop 输入源

    做了一年多的IOS开发,对IOS和Objective-C深层次的了解还十分有限,大多还停留在会用API的级别,这是件挺可悲的事情.想学好一门语言还是需要深层次的了解它,这样才能在使用的时候得心应手,出 ...

  10. HDU 4336:Card Collector(容斥原理)

    http://acm.split.hdu.edu.cn/showproblem.php?pid=4336 Card Collector Special Judge Problem Descriptio ...