蒙塔卡罗算法基本思想:
当所求解问题是某种随机事件出现的概率,或者是某个随机变量的期望值时,通过某种“实验”的方法,以这种事件出现的频率估计这一随机事件的概率,或者得到这个随机变量的某些数字特征,并将其作为问题的解。
蒙特卡洛方法的理论基础是大数定律。大数定律是描述相当多次数重复试验的结果的定律,根据这个定律知道样本数量越多,其平均就越趋近于真实值。
样例1——求圆周率:
import math
import random
m = 10000
n = 0
for i in range(m):
# x、y为0-1之间的随机数
x = random.random()
y = random.random()
# 若点(x,y) 属于图中1/4圆内 则有效个数+1
if math.sqrt(x**2 + y**2) < 1:
n += 1
# 计算pi
pi = 4 * n / m
print("pi = {}".format(pi))
结果截图:
样例2——计算函数y =x^2在[0,1]区间的定积分
import math
import random
m = 1000000
n = 0
for i in range(m):
x = random.random()
y = random.random()
if y >= x**2:
n += 1
r = n / m
print("r = {}".format(r))
结果截图:
样例三——三门问题
当参赛者转向另一扇门而不是维持原先的选择时,赢得汽车的机会将会加倍。
有三种可能的情况,全部都有相等的可能性(1/3):
参赛者挑山羊一号,主持人挑山羊二号。转换将赢得汽车。
参赛者挑山羊二号,主持人挑山羊一号。转换将赢得汽车。
“参赛者挑汽车,主持人挑羊一号。转换将失败”,和“参赛者挑汽车,主持人挑羊二号。转换将失败。”此情况的可能性为:
应用蒙特卡洛重点在使用随机数来模拟类似于赌博问题的赢率问题,并且通过多次模拟得到所要计算值的模拟值。
在三门问题中,用0、1、2分代表三扇门的编号,在[0,2]之间随机生成一个整数代表奖品所在门的编号prize,再次在[0,2]之间随机生成一个整数代表参赛者所选择的门的编号guess。用变量change代表游戏中的换门(true)与不换门(false)。
import math
import random
def play(change):
prize = random.randint(0,2)
guess = random.randint(0,2)
if guess == prize:
if change:
return False
else:
return True
else:
if change:
return True
else:
return False
def winRate(change, N):
win = 0
for i in range(N):
if(play(change)):
win += 1
print("中奖率为{}".format(win / N))
N = 1000000
print("每次换门的中奖概率:")
winRate(True,N)
print("每次都不换门的中奖概率:")
winRate(False,N)
结果截图:
补充——拟蒙特卡洛算法:
由于产生随机数的随机性,当我们用N个随机点以蒙特卡罗方法来求解具体的问题时,其计算得到近似解的误差值有大有小,但是肯定有一个确定的平均值,即一些误差大于此值,而其余误差小于此值。鉴于此,显然肯定存在这样的N个点,使得误差的绝对值不大于平均值。如果我们能够构造这样的点集就可以对原有的方法进行较大的改进。拟蒙特卡罗方法就是至于此而提出的,它致力于构造其误差比平均误差显著要好的那种点集,而其求解形式与蒙特卡罗方法一致,只不过所用的随机数不一样。用蒙特卡罗方法求解问题时,影响结果好坏的主要是随机数序列的均匀性。而拟蒙特卡罗方法中的具有低偏差的一致分布点集较伪随机数序列更为均匀,而且用拟蒙特卡罗方法求解得到的是真正的误差,避免了蒙特卡罗方法得到概率误差的缺陷。由此可见用拟蒙特卡罗方法求解问题的关键是如何找到一个均匀散布的点集。目前常用的点集有GLP点集(好格子点集,good lattice point set)、GP点集(好点集,good point set)、Halton点集及其变体、Hammersley点集等。