python编程通过蒙特卡洛法计算定积分详解

作者:冬木远景 时间:2022-05-31 10:45:01 

想当初,考研的时候要是知道有这么个好东西,计算定积分。。。开玩笑,那时候计算定积分根本没有这么简单的。但这确实给我打开了一种思路,用编程语言去解决更多更复杂的数学问题。下面进入正题。

python编程通过蒙特卡洛法计算定积分详解

如上图所示,计算区间[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

python编程通过蒙特卡洛法计算定积分详解

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

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

python编程通过蒙特卡洛法计算定积分详解

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

python编程通过蒙特卡洛法计算定积分详解

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

python编程通过蒙特卡洛法计算定积分详解

下面的例子采用一个正态分布函数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()

python编程通过蒙特卡洛法计算定积分详解

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

总结

python实现机械分词之逆向最大匹配算法代码示例

K-近邻算法的python实现代码分享

Python实现字符串匹配算法代码示例

如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

来源:http://www.cnblogs.com/21207-iHome/p/5269191.html

标签:python,蒙特卡洛,定积分
0
投稿

猜你喜欢

  • asp中常用的字符串安全处理函数集合(过滤特殊字符等)

    2011-02-20 10:40:00
  • numpy实现神经网络反向传播算法的步骤

    2021-02-11 10:54:34
  • 细数JavaScript 一个等号,两个等号,三个等号的区别

    2023-08-25 08:22:09
  • Win10下python 2.7与python 3.7双环境安装教程图解

    2022-12-14 06:03:16
  • pygame游戏之旅 游戏中添加显示文字

    2023-03-26 02:56:23
  • pytorch 获取层权重,对特定层注入hook, 提取中间层输出的方法

    2021-05-20 07:01:01
  • 由Python运算π的值深入Python中科学计算的实现

    2021-10-21 03:48:06
  • 浅析JavaScript对象转换成原始值

    2023-08-05 02:09:11
  • asp如何制作一个简单的翻页程序?

    2010-06-29 21:26:00
  • 扫盲大讲堂:SQL查询结果集对注入的影响及利用

    2009-09-05 09:49:00
  • 基于Python的科学占卜工具开发过程

    2023-01-01 03:15:05
  • opencv python 图像轮廓/检测轮廓/绘制轮廓的方法

    2022-08-13 06:54:59
  • js更好地截取字符串

    2008-03-11 19:00:00
  • python 字典操作提取key,value的方法

    2021-06-01 04:40:39
  • python使用smtplib模块发送邮件

    2023-05-16 22:25:38
  • Python对于json数据键值对遍历

    2023-02-21 06:01:08
  • 解析ROC曲线绘制(python+sklearn+多分类)

    2021-04-06 12:16:16
  • Python教程之Python多态的深层次理解

    2021-07-30 07:50:53
  • 讨论闭包传入参数:window & undefined

    2010-05-19 12:55:00
  • 详解Python中的Lock和Rlock

    2023-08-11 18:35:20
  • asp之家 网络编程 m.aspxhome.com