我最近一直在研究Monte Carlo模拟,并一直使用它来近似常数,例如(矩形内的圆,比例区域)。
但是,我无法想到使用蒙特卡洛积分来近似估计 [欧拉数] 的值的相应方法。
您对如何做到这一点有什么看法吗?
我最近一直在研究Monte Carlo模拟,并一直使用它来近似常数,例如(矩形内的圆,比例区域)。
但是,我无法想到使用蒙特卡洛积分来近似估计 [欧拉数] 的值的相应方法。
您对如何做到这一点有什么看法吗?
Answers:
本文介绍了用Monte Carlo 估计的一种简单优雅的方法。本文实际上是关于教学。因此,该方法似乎完全适合您的目标。这个想法是基于Gnedenko 一本流行的俄罗斯关于概率论的教科书中的一项练习。见p.183的ex.22e
碰巧是,其中是一个随机变量,定义如下。它是的最小值,因此和是上均匀分布的随机数。美丽,不是吗?ξ Ñ Σ Ñ 我= 1 - [R 我 > 1 - [R 我 [ 0 ,1 ]
由于这是一种练习,因此我不确定在此处发布解决方案(证明)是否对我来说很酷:)如果您想自己证明一下,这里有个提示:该章称为“ Moments”,该章应指出您朝着正确的方向前进。
如果您想自己实现它,那么请不要继续阅读!
这是用于蒙特卡洛模拟的简单算法。绘制一个均匀的随机数,然后绘制另一个,依此类推,直到总和超过1。绘制的随机数是您的第一次尝试。假设您得到了:
0.0180
0.4596
0.7920
然后,您的第一个试验将呈现3.继续进行这些试验,您会发现平均而言,您会得到。
随后是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方法中的向下序列以一个底部结束,因此,如果继续采样,您将在某个点获得另一个底部,然后在另一个位置获得一个底部。您可以跟踪它们之间的距离并建立分布。
Mean[Table[ Length[NestWhileList[(Random[]+#) &, Random[], #<1&]], {10^6}]]
R
我在西安的答案中发布的解决方案的以下直接翻译快了二十倍:n=10^6; 1. / Mean[UnitStep[Differences[Sort[RandomReal[{0, n}, n + 1]]] - 1]]
我建议赞成阿克萨卡尔的答案。它是无偏的,仅依赖于生成单位均匀偏差的方法。
我的答案可以任意精确,但仍然偏离的真实值。
西安的答案是正确的,但我认为当目的是逼近时,它对函数或生成Poisson随机偏差的方式的依赖有点循环。Ë
相反,请考虑引导过程。一个具有大量对象,它们被替换为的样本大小而绘制。在每次绘制时,未绘制特定对象的概率为,并且有绘制。从所有绘制中忽略特定对象的概率为n i 1 − n − 1 n p = (1 − 1
因为我假设我们知道
因此我们也可以写
也就是说,我们的估计值是通过估计在许多这样的重复项中从引导程序重复项省略特定观察值的概率来找到的-即引导程序中对象出现的比例。米乙Ĵ我
这种近似有两个误差源。有限的总是意味着结果是近似的,即估计是有偏差的。另外,会围绕真实值波动,因为这是模拟。p
我发现这种方法有些吸引人,因为一个本科生或另一个做得很少的人可以使用一副纸牌,一堆小石头或手头上的任何其他物品来近似,就像一个人可以估计使用指南针,直尺和一些沙粒。我认为数学可以与计算机等现代便利技术脱节是很巧妙的。π
我对各种数量的引导程序复制进行了一些模拟。标准误差是使用正常间隔估算的。
请注意,选择被引导的对象数将对结果的准确性设置绝对上限,因为蒙特卡洛过程估计且仅取决于。将设置为不必要的大值只会影响您的计算机,这是因为您只需要对进行“粗略”近似,或者因为蒙特卡洛法,偏差将被方差淹没。这些结果适用于并且近似于小数点后第三位。p p Ñ Ñ Ê Ñ = 10 3 p - 1 ≈ Ë
该图显示的选择对的稳定性具有直接而深刻的影响。蓝色虚线显示,红色虚线显示。不出所料,增加样本数量会产生更加准确的估算。 p p ë p
为此,我编写了一个令人尴尬的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')
解决方案1:
对于泊松分布,因此,如果, 这意味着您可以估算通过泊松模拟。泊松模拟可以从指数分布生成器中获得(如果不是以最有效的方式)。P(X = ķ )= λ ķ X 〜P(1 )P(X = 0 )= P(X = 1 )= ë - 1 ë - 1
备注1:正如评论中所讨论的,这是一个相当复杂的论点,因为从泊松分布或等效指数分布进行模拟可能很难想象,而不涉及对数或exp 函数。但是后来W. Huber提出了通过基于有序制服的最优雅解决方案来挽救该答案。但是,这是一个近似值,因为均匀间距为Beta,这意味着会聚到作为
增长到无限。另一方面,冯·诺伊曼(von Neumann)1951年的指数生成器仅使用统一代。
解决方案2:
将常数表示为整数的另一种方法是回想一下,当则,它也是分布。因此, 通过逼近的第二种方法因此,蒙特卡洛将模拟法线对并监视的出现频率。从某种意义上讲,它与蒙特卡罗近似相反,后者与 ... 的出现频率有关。
解决方案3:
我的沃里克大学同事波洛克(M. Pollock)指出了另一种称为福赛斯(Forsythe)方法的蒙特卡洛近似:这个想法是运行一系列均匀的代直到。那么,对应的停止规则的期望值即是均匀序列下降的时间,而为奇数的概率为!(Forsythe的方法实际上旨在从形式的任何密度进行模拟,因此比近似和更通用。)
这与阿克萨卡(Aksakal)的答案中使用的格涅坚科(Gnedenko)的方法非常相似,因此我想知道是否可以从另一方派生出来。至少,两者具有相同的分布,概率质量为对于值。
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)
n <- 1e5; 1/mean(n*diff(sort(runif(n+1))) > 1)
不是解决方案...只是快速评论,对于评论框来说太长了。
阿克萨卡尔族
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的估计值:
...都在Mathematica中。下图对比了所得数据A和数据B数据集的非参数内核密度估计。
因此,尽管胡布尔的代码(红色曲线)的速度大约是后者的两倍,但该方法似乎并不“可靠”。
running four times as many iterations will make them equally accurate
///// .....对此有一个快速的发挥:将西安方法1中使用的采样点数量从增加到6 x(即,数量的6倍)。点)产生与Aksaksal类似的曲线。10 6
方法需要大量的样本
首先,您需要能够从正态分布中采样。假设您要排除使用函数或查找从该函数派生的表,则可以通过CLT从正态分布中生成近似样本。例如,如果您可以从统一(0,1)分布中采样,则。正如whuber所指出的那样,要在样本大小接近拥有最终的估计方法,则当样本大小接近无穷大时,将要求使用的统一样本数量接近。ˉ X √
现在,如果可以从具有足够大样本的正态分布中进行采样,则可以得到密度的一致估计。这可以使用直方图或内核平滑器来完成(但请注意不要使用高斯内核来遵循您的no规则!)。为了使密度估计值保持一致,您需要让df(直方图中的bin数,窗口的倒数以便更平滑)接近无穷大,但要慢于样本大小。
所以现在,有了大量的计算能力,您可以近似得出的密度,即。由于,因此您对的估计值。
如果您想一头雾水,甚至可以使用前面讨论的方法估算和。
该方法只需要很少的样本,但是会引起不合理的数值误差
根据我的评论,这是一个完全愚蠢但非常有效的答案:
令。定义。定义。
这将收敛非常快,但也碰上极端数值误差。
whuber指出,这使用了幂函数,通常称为exp函数。可以通过离散化来避免这种情况,以使是整数,并且可以通过重复乘法来代替幂。要求随着,的离散化会越来越精细,并且离散化必须排除。有了这个,理论上的估计量(即不存在数值误差的世界)将收敛到,而且非常快!
这是另一种可以完成的方法,尽管速度很慢。我不要求效率,但本着完整性的精神提供这种替代方法。
相对于西安市的答案,出于该问题的目的,我将假定您能够生成并使用均匀的伪随机变量,然后您需要使用基本算术运算通过某种方法来估计(即,您不能使用对数或指数函数或使用这些函数的任何分布)。 本方法由涉及统一随机变量的简单结果所激发:ù 1,⋯ ,û Ñ〜IIDù (0 ,1 )È †
使用此结果估计:我们首先将样本值按降序排列以获得阶数统计,然后定义部分和:
现在,让,然后通过对有序均匀变量进行插值来估计。这给出了的估计量, 由下式给出:
该方法有一些轻微的偏差(由于截止点为的线性插值),但它是的一致估计。该方法可以很容易地实现,但是它需要对值进行排序,这比确定性计算要消耗更多的计算量。此方法很慢,因为它涉及对值进行排序。
作为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]); }
实现此代码可使的真实值收敛,但与确定性方法相比,它非常慢。
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
我认为我们希望避免使用任何涉及指数或对数的转换的方法。如果我们可以使用在其定义中使用指数的密度,则可以使用密度调用从这些代数中得出。
R
命令的2 + mean(exp(-lgamma(ceiling(1/runif(1e5))-1)))
作用,可能会变得如此明显。(如果使用log Gamma函数困扰您,请将其替换为2 + mean(1/factorial(ceiling(1/runif(1e5))-2))
,它仅使用加法,乘法,除法和截断,而忽略溢出警告。)可能更有意义的是高效的模拟:您能否将估计到任何给定精度所需的计算步骤?