R语言蒙特卡罗Monte Carlo方法进行数值积分和模拟可视化

发布时间 2023-12-14 23:12:10作者: 拓端tecdat

全文链接:https://tecdat.cn/?p=34556

原文出处:拓端数据部落公众号

蒙特卡罗方法的常见用途是对可能难以通过解析积分的函数执行数值积分。这可能看起来很奇怪,但直觉是相当简单的。关键是几何思维问题,并将其与概率连接。让我们采取一个简单的多项式函数,用y = x ^ 2来说明这个想法。

假设我们想要找到这个函数的积分,但是我们不知道如何从分析中得到它。 现在,如果我们随机地将米粒(理想地点)投入箱中,则曲线下方的谷物数量与箱的总面积的比将收敛于积分。直观地来说,这是有意义的,因为如果框中的每个点具有相等的被计数的概率,则事件(点在曲线下方)的总概率与曲线下面积相同是合理的。实际上,绘制10000个随机点似乎填满了盒子。

 
 
n <- 10000  
f <- fnton(x) x^2  lot(rni(n),ruif(n) ol='be',h20)  
cue(f, 0,1, n=100, col'he'addTRUE)

image.png

现在我们如何从一个均匀分布在一个盒子中的点得到积分的近似值? 为了回答这个问题,让我们考虑一下这个 “曲线下面积”。 这是告诉我们,曲线下的点是重要的。 因此,对于给定的x值,y值必须小于同一点处的函数值。

 
 
ps <- mrunif(2*n), ncl=2)  
g <- funcx,y) y <= x^2  
z <- g([,1] ps[,2])  
plt(ps[!z,1], ps[!z,2], 
(f, 0,1, n=100, lE)

QQ截图20231128144503.png

简单的说,积分就是曲线下所有点的计数除以总点数,这是点落在曲线下的概率。 > length(z[z]) / n [1] 0.3325 注意,该方法不限于计算积分。 它甚至可以用于近似无理数如 pi。 稍后我们将探讨这种情况。

近似误差和数值稳定性

数值近似似乎有用,但我们如何知道近似是否好? 为了回答这个问题,我们需要考虑近似误差。 让我们先来看看随着我们增加点的数量,近似值是如何变化的。

 
 
ks <- 1:7  
g <- fcin(k) {  
  n <- 10^k  
  f <- fucin(x,y) y <= x^2  
  z <- f(ruif(n), rnif(n))  
  leth(z[z]) / n  
}  
a <- sapy(ks,g)
a

image.png

从这个特定的实现来看,似乎近似收敛,虽然有些缓慢。 请记住,上面的每个近似值都需要一个数量级的样本来产生结果。 有100万点,误差约为0.038%。 我们需要多少分才能达到0.01%以下? 从Grinstead和Snell,我们知道错误将在95%的时间内在 frac {1} { sqrt {n}}内,这意味着一百万个试验应该达到0.0003162278或0.032%的精度。 因此,我们需要运行1000万次试验,以达到95%概率的精度。 作为 检查,在我第一次尝试我得到0.009071%,这看起来不错。

当近似值随着迭代次数的增加而提高时,这被称为数值稳定性。 绘制理论极限和实际误差表明,使用足够的条件,两个似乎收敛。

 
 
ot(ks, 1/st(10^ks), ye='l')  
lis(ks, as(1/3 - a),)

image.png

然而,试图在抽象中回答这一点是一个错误。 对精度的需求是具体情况,因此没有固定的规则可以遵循。 它类似于病例特异性的显着性检验。 关键是要达到足够的精度,使您的结果不会在使用时产生噪音。

估计 pi 现在是时候把注意力转向 pi。 如前所述,可以使用蒙特卡罗方法来估计 pi。 对于这种情况,我使用圆的方程来定义面积。 由于单位圆具有 pi的面积,其四分之一将具有面积 frac { pi} {4}。 因此,最终结果将需要乘以4以获得最终近似。

 
 
g <- fnon(k) {  
  n <- 10^k  
  f <- fucon(x,y) sqrt(x^2 + y^2) <= 1  
  lgh(z[z]) / n  
}  
a <- sapply(1:7, g)

a*4

image.png

类似于 int_0 ^ 1 x ^ 2 dx的近似, pi的近似似乎跳转,尽管收敛到真实值。 对于给定次数的试验,值的跳跃量与近似误差有关。 除了知道必须模拟多少迭代以获得精确近似之外,知道给定近似可以偏离多少也是重要的。 我们可以通过反复运行相同迭代次数的模拟来观察这一点。

 
 
tils <- 4 * sply(rep(6,100), g)  
e <- 1/sqt(10^6)

ma(trils) 

leth(trals[bs(rils - pi)/pi <= e]) 

image.png

除了近似误差,关于蒙特卡罗方法有趣的是,许多问题可以通过将问题转换成蒙特卡罗方法的形式来解决。

模拟

蒙特卡罗方法的常见用途是用于模拟。 不是近似函数或数字,目标是基于模拟通过过程的多个路径来理解结果的分布或集合。 正如Grinstead&Snell所描述的,一个简单的模拟是多次掷硬币。 这里我们使用均匀分布并将实值输出转换为集合 left  {-1,1  right }。 (样本函数可以直接做到这一点,但这是更多的说明。)

 
 
r <- ruif(1000)  
s <- ese(r > .5, 1, -1)  
plot(cmm(toss), ='l')

image.png

掷硬币

这个模拟显示了我们在随机扔硬币1000次后发生了什么。 很难从这里收集很多信息,但如果我们做同样的实验1000次,现在我们可以看到可能结果的良好表示。 给定这组结果,可以计算统计特征来表征分布的属性。 当不遵循已知分布时,这是有用的。

 
 
oucos <- sppy(1:1000, fnon(i) sum(ifse(ruif(1000) > .5, 1, -1)))  
hist(otcmes)

image.png

CCUS-1536x15361.jpg