使用蒙特卡洛模拟的近似


35

我最近一直在研究Monte Carlo模拟,并一直使用它来近似常数,例如(矩形内的圆,比例区域)。π

但是,我无法想到使用蒙特卡洛积分来近似估计 [欧拉数] 的值的相应方法。e

您对如何做到这一点有什么看法吗?


7
有很多很多方法可以做到这一点。通过考虑该R命令的2 + mean(exp(-lgamma(ceiling(1/runif(1e5))-1)))作用,可能会变得如此明显。(如果使用log Gamma函数困扰您,请将其替换为2 + mean(1/factorial(ceiling(1/runif(1e5))-2)),它仅使用加法,乘法,除法和截断,而忽略溢出警告。)可能更有意义的是高效的模拟:您能否将估计到任何给定精度所需的计算步骤?e
ub

4
多么令人高兴的问题!我期待阅读别人的答案。您可以真正引起人们对这个问题的注意的一种方法-也许是另外六个答案- 就像胡布尔建议的那样,修改问题并寻求有效的答案。这就像简历用户的猫薄荷。
恢复莫妮卡

1
@EngrStudent我不确定的几何类似物是否存在。它根本不是像这样的自然(双关语意)几何量。eπ
阿克萨卡尔州

6
@Aksakal是一个特殊的几何量。在最基本的层次上,它自然出现在与双曲线相关的区域的表达式中。在更高的层次上,它与所有周期函数(包括三角函数)紧密相连,包括几何内容很明显的三角函数。真正的挑战在于,模拟与相关的值非常容易eee
ub

2
@StatsStudent:本身并不有趣。但是,如果这导致对类的量进行无偏估计,则可能对MCMC算法最有用。e
exp{0xf(y)dG(y)}
西安

Answers:


34

本文介绍了用Monte Carlo 估计的一种简单优雅的方法。本文实际上是关于教学。因此,该方法似乎完全适合您的目标。这个想法是基于Gnedenko 一本流行的俄罗斯关于概率论教科书中的一项练习。见p.183的ex.22eee

碰巧是,其中是一个随机变量,定义如下。它是的最小值,因此和是上均匀分布的随机数。美丽,不是吗?ξ Ñ Σ Ñ = 1 - [R > 1 - [R [ 0 1 ]E[ξ]=eξni=1nri>1ri[0,1]

由于这是一种练习,因此我不确定在此处发布解决方案(证明)是否对我来说很酷:)如果您想自己证明一下,这里有个提示:该章称为“ Moments”,该章应指出您朝着正确的方向前进。

如果您想自己实现它,那么请不要继续阅读!

这是用于蒙特卡洛模拟的简单算法。绘制一个均匀的随机数,然后绘制另一个,依此类推,直到总和超过1。绘制的随机数是您的第一次尝试。假设您得到了:

 0.0180
 0.4596
 0.7920

然后,您的第一个试验将呈现3.继续进行这些试验,您会发现平均而言,您会得到。e

随后是MATLAB代码,仿真结果和直方图。

N = 10000000;
n = N;
s = 0;
i = 0;
maxl = 0;
f = 0;
while n > 0
    s = s + rand;
    i = i + 1;
    if s > 1
        if i > maxl
            f(i) = 1;
            maxl = i;
        else
            f(i) = f(i) + 1;
        end
        i = 0;
        s = 0;
        n = n - 1;
    end
end

disp ((1:maxl)*f'/sum(f))
bar(f/sum(f))
grid on

f/sum(f)

结果和直方图:

2.7183


ans =

  Columns 1 through 8

         0    0.5000    0.3332    0.1250    0.0334    0.0070    0.0012    0.0002

  Columns 9 through 11

    0.0000    0.0000    0.0000

在此处输入图片说明

更新:我更新了我的代码以摆脱试验结果的数组,以便不占用RAM。我还打印了PMF估计。

更新2:这是我的Excel解决方案。在Excel中放置一个按钮,并将其链接到以下VBA宏:

Private Sub CommandButton1_Click()
n = Cells(1, 4).Value
Range("A:B").Value = ""
n = n
s = 0
i = 0
maxl = 0
Cells(1, 2).Value = "Frequency"
Cells(1, 1).Value = "n"
Cells(1, 3).Value = "# of trials"
Cells(2, 3).Value = "simulated e"
While n > 0
    s = s + Rnd()
    i = i + 1
    If s > 1 Then
        If i > maxl Then
            Cells(i, 1).Value = i
            Cells(i, 2).Value = 1
            maxl = i
        Else
            Cells(i, 1).Value = i
            Cells(i, 2).Value = Cells(i, 2).Value + 1
        End If
        i = 0
        s = 0
        n = n - 1
    End If
Wend


s = 0
For i = 2 To maxl
    s = s + Cells(i, 1) * Cells(i, 2)
Next


Cells(2, 4).Value = s / Cells(1, 4).Value

Rem bar (f / Sum(f))
Rem grid on

Rem f/sum(f)

End Sub

在单元格D1中输入试验次数,例如1000,然后单击按钮。第一次运行后,屏幕如下所示:

在此处输入图片说明

更新3:Silverfish启发了我另一种方式,虽然不如第一种优雅,但仍然很酷。它使用Sobol序列计算了n个简单体的体积。

s = 2;
for i=2:10
    p=sobolset(i);
    N = 10000;
    X=net(p,N)';
    s = s + (sum(sum(X)<1)/N);
end
disp(s)

2.712800000000001

巧合的是,他写了第一关于我在高中时读过的蒙特卡洛方法的。我认为这是对该方法的最佳介绍。

更新4:

Silverfish在注释中建议了一个简单的Excel公式实现。通过大约一百万个随机数和185K次试验,您可以用他的方法得到这种结果:

在此处输入图片说明

显然,这比Excel VBA实施要慢得多。特别是,如果您修改我的VBA代码以不更新循环内的单元格值,并且仅在收集完所有统计信息后才执行此操作。

更新5

西安的解决方案 3密切相关(甚至在某种意义上与jwg在线程中的注释相同)。很难说谁首先提出了这个想法,例如Forsythe或Gnedenko。格涅坚科(Gnedenko)最初的1950年俄语版的“章节”中没有“问题”部分。因此,乍一看在以后的版本中都找不到这个问题。也许是后来添加或掩埋在文本中。

正如我在西安的答案中评论的那样,福赛斯的方法与另一个有趣的领域有关:随机(IID)序列中峰(极值)之间的距离分布。平均距离恰好为3。Forsythe方法中的向下序列以一个底部结束,因此,如果继续采样,您将在某个点获得另一个底部,然后在另一个位置获得一个底部。您可以跟踪它们之间的距离并建立分布。


哇,太酷了!您能否添加一两个段落来说明其工作原理?
恢复莫妮卡

7
(+1)辉煌!答案是最高分,因为它仅依赖于统一的模拟。并且不使用任何近似值,而是由于蒙特卡洛而得到的近似值。它与Gnedenko的连接又是另一回事。
西安

2
凉!这是Mathematica的同一代码,就像单行代码一样:
Mean[Table[ Length[NestWhileList[(Random[]+#) &, Random[], #<1&]], {10^6}]]
wolfies

4
@wolfies R我在西安的答案中发布的解决方案的以下直接翻译快了二十倍:n=10^6; 1. / Mean[UnitStep[Differences[Sort[RandomReal[{0, n}, n + 1]]] - 1]]
笨蛋

1
我已经发布了“为什么意思是?” 将问题作为一个问题本身 ; 我怀疑我的草图解决方案(这是问题的“明显”可视化立即想到的)并不一定是俄罗斯学生打算这样做的方式!因此,替代解决方案将非常受欢迎。e
Silverfish

19

我建议赞成阿克萨卡尔的答案。它是无偏的,仅依赖于生成单位均匀偏差的方法。

我的答案可以任意精确,但仍然偏离的真实值。e

西安的答案是正确的,但我认为当目的是逼近时,它对函数或生成Poisson随机偏差的方式的依赖有点循环。Ëloge

通过自举估计e

相反,请考虑引导过程。一个具有大量对象,它们被替换为的样本大小而绘制。在每次绘制时,绘制特定对象的概率为,并且有绘制。从所有绘制中忽略特定对象的概率为n i 1 n 1 n p = 1 1nni1n1np=(11n)n.

因为我假设我们知道

exp(1)=limn(11n)n

因此我们也可以写

exp(1)p^=i=1mIiBjm

也就是说,我们的估计值是通过估计在许多这样的重复项中从引导程序重复项省略特定观察值的概率来找到的-即引导程序中对象出现的比例。ĴpmBji

这种近似有两个误差源。有限的总是意味着结果是近似的,即估计是有偏差的。另外,会围绕真实值波动,因为这是模拟。pnp^

我发现这种方法有些吸引人,因为一个本科生或另一个做得很少的人可以使用一副纸牌,一堆小石头或手头上的任何其他物品来近似,就像一个人可以估计使用指南针,直尺和一些沙粒。我认为数学可以与计算机等现代便利技术脱节是很巧妙的。πeπ

结果

我对各种数量的引导程序复制进行了一些模拟。标准误差是使用正常间隔估算的。

请注意,选择被引导的对象数将对结果的准确性设置绝对上限,因为蒙特卡洛过程估计且仅取决于。将设置为不必要的大值只会影响您的计算机,这是因为您只需要对进行“粗略”近似,或者因为蒙特卡洛法,偏差将被方差淹没。这些结果适用于并且近似于小数点后第三位。p p Ñ Ñ Ê Ñ = 10 3 p - 1Ënppnnen=103p1e

该图显示的选择对的稳定性具有直接而深刻的影响。蓝色虚线显示,红色虚线显示。不出所料,增加样本数量会产生更加准确的估算。 p p ë pmp^pep^在此处输入图片说明

为此,我编写了一个令人尴尬的R脚本。可以在20美元的钞票背面提出改善建议。

library(boot)
library(plotrix)
n <- 1e3

## if p_hat is estimated with 0 variance (in the limit of infinite bootstraps), then the best estimate we can come up with is biased by exactly this much:
approx <- 1/((1-1/n)^n)

dat <- c("A", rep("B", n-1))
indicator <- function(x, ndx)   xor("A"%in%x[ndx], TRUE) ## Because we want to count when "A" is *not* in the bootstrap sample

p_hat <- function(dat, m=1e3){
    foo <- boot(data=dat, statistic=indicator, R=m) 
    1/mean(foo$t)
} 

reps <- replicate(100, p_hat(dat))

boxplot(reps)
abline(h=exp(1),col="red")

p_mean <- NULL
p_var <- NULL
for(i in 1:10){
    reps <- replicate(2^i, p_hat(dat))
    p_mean[i] <- mean(reps)
    p_var[i] <- sd(reps)
}
plotCI(2^(1:10), p_mean, uiw=qnorm(0.975)*p_var/sqrt(2^(1:10)),xlab="m", log="x", ylab=expression(hat(p)), main=expression(paste("Monte Carlo Estimates of ", tilde(e))))
abline(h=approx, col='red')

4
+1这很有意义。如果编写了代码,您是否有机会共享代码?
Antoni

2
即使这可以任意精确,但最终还是不能令人满意的,因为它仅模拟的近似值,而不模拟本身。eee
ub

1
当然。您只需要在另一个内部进行一个重复调用即可,这与我们现在的基本相同。
恢复莫妮卡

1
@whuber我真的看不到对的任意精确近似与对本身的任意精确近似之间的区别。eee
jwg '16

1
@jwg除了在概念上很重要之外,在实际中也很重要,因为对逼近实施逼近需要跟踪两个逼近中每个逼近的精度。但是我必须同意,当两种近似都可以接受时,整体方法确实很好。
whuber

14

解决方案1:

对于泊松分布,因此,如果, 这意味着您可以估算通过泊松模拟。泊松模拟可以从指数分布生成器中获得(如果不是以最有效的方式)。PX = ķ = λ ķP(λ) X P1 PX = 0 = PX = 1 = ë - 1 ë - 1

P(X=k)=λkk!eλ
XP(1)
P(X=0)=P(X=1)=e1
e1

备注1:正如评论中所讨论的,这是一个相当复杂的论点,因为从泊松分布或等效指数分布进行模拟可能很难想象,而不涉及对exp 函数。但是后来W. Huber提出了通过基于有序制服的最优雅解决方案来挽救该答案。但是,这是一个近似值,因为均匀间距为Beta,这意味着会聚到作为U(i:n)U(i1:n)B(1,n)

P(n{U(i:n)U(i1:n)}1)=(11n)n
e1n增长到无限。另一方面,冯·诺伊曼(von Neumann)1951年的指数生成器使用统一代。

解决方案2:

将常数表示为整数的另一种方法是回想一下,当则,它也是分布。因此, 通过逼近的第二种方法因此,蒙特卡洛将模拟法线对并监视的出现频率。从某种意义上讲,它与蒙特卡罗近似相反,后者与 ... 的出现频率有关。e

X1,X2iidN(0,1)
(X12+X22)χ12
E(1/2)
P(X12+X222)=1{1exp(2/2)}=e1
e(X1,X2)X12+X222πX12+X22<1

解决方案3:

我的沃里克大学同事波洛克(M. Pollock)指出了另一种称为福赛斯(Forsythe)方法的蒙特卡洛近似:这个想法是运行一系列均匀的代直到。那么,对应的停止规则的期望值即是均匀序列下降的时间,而为奇数的概率为!(Forsythe的方法实际上旨在从形式的任何密度进行模拟,因此比近似和更通用。)u1,u2,...un+1>unNeNe1expG(x)ee1

这与阿克萨卡(Aksakal)的答案中使用的格涅坚科(Gnedenko)的方法非常相似,因此我想知道是否可以从另一方派生出来。至少,两者具有相同的分布,概率质量为对于值。1/n!n

Forsythe方法的快速R实现是放弃精确遵循统一的顺序,转而使用较大的块,从而允许并行处理:

use=runif(n)
band=max(diff((1:(n-1))[diff(use)>0]))+1
bends=apply(apply((apply(matrix(use[1:((n%/%band)*band)],nrow=band),
2,diff)<0),2,cumprod),2,sum)

12
只要知道如何在不知道情况下进行泊松仿真。e
Glen_b

5
如果我调用R rpoiss()生成器,我可以假装不知道。更严重的是,您可以使用[函数而不是 ] 生成指数变量直到总和超过并且结果数减1就是泊松。E1 log e 1 P1 eE(1)loge1P(1)
西安

5
计算等同于计算,因为它们是相反的。您可以避免以各种方式计算任何此类函数。这是一个基于您的第一个答案的解决方案: 它仅使用基本算术。explogexpn <- 1e5; 1/mean(n*diff(sort(runif(n+1))) > 1)
ub

3
我相信Forsythe的方法与Gnedenko的方法相同。选择统一的使得小于1等于选择小于,如果成功,则选择在和0 之间有条件地均匀分布n x i x n 1 n 1 x i 1 n x i 1 n 1 x ixnnxixn1n1xi1nxi1n1xi
。– jwg

3
我不知道Forsythe的方法。但是,它与其他非常有趣的东西相关。如果不是在停止你不停地采样,然后从距离的预期到下一个底部恰好是3nn+1n
Aksakal

7

不是解决方案...只是快速评论,对于评论框来说太长了。

阿克萨卡尔族

Aksakal发布了一个解决方案,在该解决方案中,我们计算了必须采取的标准统一图纸的预期数量,以使它们的总和超过1。在Mathematica中,我的第一个公式是:

mrM := NestWhileList[(Random[] + #) &, Random[], #<1 &]

Mean[Table[Length[mrM], {10^6}]] 

编辑:对此进行了快速操作,以下代码(相同的方法-在Mma中-只是不同的代码)大约快10倍:

Mean[Table[Module[{u=Random[], t=1},  While[u<1, u=Random[]+u; t++]; t] , {10^6}]]

西安/惠伯

Whuber建议使用快速的代码来模拟Xian的解决方案1:

R版本: n <- 1e5; 1/mean(n*diff(sort(runif(n+1))) > 1)

Mma版本: n=10^6; 1. / Mean[UnitStep[Differences[Sort[RandomReal[{0, n}, n + 1]]] - 1]]

他指出,这比第一个代码快20倍(或比上面的新代码快两倍)。

只是为了好玩,我认为看看两种方法是否同样有效(从统计意义上来说)会很有趣。为此,我使用以下方法生成了2000个e的估计值:

  • 阿克萨卡尔的方法:dataA
  • 西安的方法1,使用操作代码:dataB

...都在Mathematica中。下图对比了所得数据A和数据B数据集的非参数内核密度估计。

在此处输入图片说明

因此,尽管胡布尔的代码(红色曲线)的速度大约是后者的两倍,但该方法似乎并不“可靠”。


真实值位置的垂直线将大大改善此图像。
恢复莫妮卡

1
这是一个非常有趣的观察,谢谢。由于半角宽度将随模拟的大小四次缩放,而西安方法的半角宽度大约是阿克萨卡尔方法的一半,因此运行四倍的迭代将使它们具有相同的精度。每次迭代需要多少工作量的问题仍然存在:如果西安方法的一次迭代所需的工作量不到四分之一,那么该方法仍然会更有效。
whuber

1
我相信当您比较两种方法所需的随机变量的实现数量而不是标称值时,情况会变得很清楚。n
ub

1
@whuber写道:running four times as many iterations will make them equally accurate///// .....对此有一个快速的发挥:将西安方法1中使用的采样点数量从增加到6 x(即,数量的6倍)。点)产生与Aksaksal类似的曲线。10 6106106
Wolfies '16

1
代码做得很好-很难对此进行很大的改进。
whuber

2

方法需要大量的样本

首先,您需要能够从正态分布中采样。假设您要排除使用函数或查找从该函数派生的表,则可以通过CLT从正态分布中生成近似样本。例如,如果您可以从统一(0,1)分布中采样,则。正如whuber所指出的那样,要在样本大小接近拥有最终的估计方法,则当样本大小接近无穷大时,将要求使用的统一样本数量接近。ˉ Xf(x)=exx¯12n˙N(0,1)e

现在,如果可以从具有足够大样本的正态分布中进行采样,则可以得到密度的一致估计。这可以使用直方图或内核平滑器来完成(但请注意不要使用高斯内核来遵循您的no规则!)。为了使密度估计值保持一致,您需要让df(直方图中的bin数,窗口的倒数以便更平滑)接近无穷大,但要慢于样本大小。N(0,1)ex

所以现在,有了大量的计算能力,您可以近似得出的密度,即。由于,因此您对的估计值。N(0,1)ϕ^(x)ϕ((2))=(2π)1/2e1e=ϕ^(2)2π

如果您想一头雾水,甚至可以使用前面讨论的方法估算和。22π

该方法只需要很少的样本,但是会引起不合理的数值误差

根据我的评论,这是一个完全愚蠢但非常有效的答案:

令。定义。定义。Xuniform(1,1)Yn=|(x¯)n|e^=(1Yn)1/Yn

这将收敛非常快,但也碰上极端数值误差。

whuber指出,这使用了幂函数,通常称为exp函数。可以通过离散化来避免这种情况,以使是整数,并且可以通过重复乘法来代替幂。要求随着,的离散化会越来越精细,并且离散化必须排除。有了这个,理论上的估计量(即不存在数值误差的世界)将收敛到,而且非常快!Yn1/YnnYnYn=0e


2
CLT方法并不令人满意,因为最终您知道这些值不是正态分布的。但是有很多方法可以生成正态变量而无需或对数:Box-Muller方法是一种。但是,该函数需要三角函数,并且(在基本层次上)这些函数与指数函数相同。e
ub

1
@whuber:我没有使用Box-Muller,因为所需的对数转换过于直接地转化为本书中的指数。我本来会反感cos和罪过,但这只是因为我暂时忘记了复杂的分析,所以很不错。
Cliff AB

1
但是,我会认为生成的法线逼近是该想法的弱点。密度估计甚至更弱!您可以想到具有两个参数的想法:,在“近似法线”中使用的数,以及在处估计密度的数。随着和接近,估计量将接近。实际上,我非常有信心比限制收敛速度;非参数密度的收敛速度很慢!n1n2ϕ(2)n1n2en2n1
悬崖AB

2

这是另一种可以完成的方法,尽管速度很慢。我不要求效率,但本着完整性的精神提供这种替代方法。

相对于西安市的答案,出于该问题的目的,我将假定您能够生成并使用均匀的伪随机变量,然后您需要使用基本算术运算通过某种方法来估计(即,您不能使用对数或指数函数或使用这些函数的任何分布)。 本方法由涉及统一随机变量的简单结果所激发:ù 1û ÑIIDù 0 1 È nU1,,UnIID U(0,1)e

E(I(Ui1/e)Ui)=1/e1duu=1.

使用此结果估计:e我们首先将样本值按降序排列以获得阶数统计,然后定义部分和:u(1)u(n)

Sn(k)1ni=1k1u(i)for all k=1,..,n.

现在,让,然后通过对有序均匀变量进行插值来估计。这给出了的估计量, 由下式给出:mmin{k|S(k)1}1/ee

e^2u(m)+u(m+1).

该方法有一些轻微的偏差(由于截止点为的线性插值),但它是的一致估计。该方法可以很容易地实现,但是它需要对值进行排序,这比确定性计算要消耗更多的计算量。此方法很慢,因为它涉及对值进行排序。1/eee

作为R实现: 该方法可以被实现R使用runif以产生均匀的值。代码如下:

EST_EULER <- function(n) { U <- sort(runif(n), decreasing = TRUE);
                           S <- cumsum(1/U)/n;
                           m <- min(which(S >= 1));
                           2/(U[m-1]+U[m]); }

实现此代码可使的真实值收敛,但与确定性方法相比,它非常慢。e

set.seed(1234);

EST_EULER(10^3);
[1] 2.715426

EST_EULER(10^4);
[1] 2.678373

EST_EULER(10^5);
[1] 2.722868

EST_EULER(10^6); 
[1] 2.722207

EST_EULER(10^7);
[1] 2.718775

EST_EULER(10^8);
[1] 2.718434

> exp(1)
[1] 2.718282

我认为我们希望避免使用任何涉及指数或对数的转换的方法。如果我们可以使用在其定义中使用指数的密度,则可以使用密度调用从这些代数中得出。e

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.