- 文章原作者:新缸中之脑
- 文章链接:https://www.toutiao.com/i7028498316396839432/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1×tamp=1638613017&app=news_article&utm_source=weixin&utm_medium=toutiao_ios&use_new_style=1&req_id=2021120418165701015015608914163D60&share_token=01C2E436-7124-40A6-B871-E04C0656CE78&group_id=7028498316396839432
蒙特卡洛仿真(或概率仿真)是一种用于了解金融部门风险和不确定性、项目管理、成本和其他预测机器学习模型的影响的技术。
风险分析是我们做出的几乎每一个决定的一部分,因为我们经常面临生活中的不确定性、模糊性和多变性。此外,即使我们获得了前所未有的信息,我们也不能准确预测未来。
蒙特卡洛仿真使我们能够看到所有可能的结果,并评估风险影响,从而允许在不确定性下更好的决策。
在本文中,我们将通过五个不同的示例来理解蒙特卡洛仿真方法。本教程的代码可在Github及Google Colab 找到。
1、 掷硬币翻转示例
掷一个无偏硬币的正面向上的概率为 1/2。然而,我们有什么办法可以实验证明吗?在此示例中,我们将使用蒙特卡洛方法模拟掷硬币 5000 次,以找出为什么正面向上的概率始终为 1/2。如果我们重复掷这个硬币很多很多次,那么可以达到更高的准确性。
## 导入库
import random
import numpy as np
import matplotlib.pyplot as plt
## 投硬币的函数
def coin_filp():return random.randint(0,1) # 产生01随机数
## Monte Carlo Simulationprob_list1 = [] # 空列表存储概率值def monte_carlo(n):"""n 是模拟次数"""results = 0for i in range(n):flip_result = coin_filp()results =results + flip_result# Calculating probability valueprob_value = results/(i+1)# append the probability values to the listprob_list1.append(prob_value)# plot the resultsplt.axhline(y = 0.5,color = 'red',linestyle='-')plt.xlabel('Iterations')plt.ylabel('Probability')plt.plot(prob_list1)return results/n
# calling the functionanswer = monte_carlo(5000)
print('Final value:',answer)
Final value: 0.4968
如上图所示,我们在 5000 次迭代后,获得正面向上的概率为 0.502。因此,这就是我们如何使用蒙特卡洛仿真来找到概率值的实验。
2.估计Π(pi)
要估计 PI 的价值,我们需要正方型和圆的面积。为了找到这些区域,我们将随机将点放在表面上,并计算落在圆圈内的点和落在正方形内的点。这将给我们估计他们的面积。因此,我们将使用点计数作为区域,而不是使用实际区域的大小。
## 导入库
import turtle
import random
import matplotlib.pyplot as plt
import math
## 绘制点
# to visualize the random points
mypen = turtle.Turtle()
mypen.hideturtle()
mypen.speed(0)# drawing a square
mypen.up()
mypen.setposition(-100,-100)
mypen.down()
mypen.fd(200)
mypen.left(90)
mypen.fd(200)
mypen.left(90)
mypen.fd(200)
mypen.left(90)
mypen.fd(200)
mypen.left(90)# drawing a circle
mypen.up()
mypen.setposition(0,-100)
mypen.down()
mypen.circle(100)
# 初始化数据
# to count the points inside and outside the circle
in_circle = 0
out_circle = 0# to store the values of the PI
pi_values = []
# 主函数
# running for 5 times
for i in range(5):for j in range(50):# generate random numbers x = random.randrange(-100,100)y = random.randrange(-100,100)# check if the number lies outside the circleif (x**2+y**2>100**2):mypen.color('black')mypen.up()mypen.goto(x,y)mypen.down()mypen.dot()out_circle = out_circle + 1else:mypen.color('red')mypen.up()mypen.goto(x,y)mypen.down()mypen.dot()in_circle = in_circle + 1# calculating the value of PIpi = 4.0 * in_circle/(in_circle + out_circle)# append the values of PI in listpi_values.append(pi)# Calculating the errorsavg_pi_errors = [abs(math.pi - pi) for pi in pi_values]# Print the final values of PI for each iterationsprint(pi_values[-1])
3.12
2.96
2.8533333333333335
3.0
3.04
# 绘制图像
# Plot the PI values
plt.axhline(y=math.pi,color='g',linestyle='-')
plt.plot(pi_values)
plt.xlabel('Iterations')
plt.ylabel('Values of PI')
plt.show()
plt.axhline(y = 0.0,color = 'g',linestyle='-')
plt.plot(avg_pi_errors)
plt.xlabel('Iterations')
plt.ylabel('Error')
plt.show()
3.Monty Hall问题
假设在一个游戏节目中, 你可以选择三扇门之一: 一扇门后面是一辆车; 其他门后面都是山羊。你挑一扇门,比方说门1,主持人,他知道门后面是什么,打开另一扇门,比如说门3,有一只山羊。主持人然后问你:你是要坚持你的选择还是选择另一扇门?
换门对你有利吗?
根据概率,换门对我们是有利的。让我们了解一下:
最初,对于所有三个门,获得汽车的概率(P)是相同的(P = 1/3)。
现在假设参赛者选择门 1。然后主持人打开第三扇门,门后面有一只山羊。接下来,主持人问参赛者是否想换门?
我们将看到为什么换门更有利:
在上图中,我们可以看到,在主持人打开3号门后,两扇门拥有汽车的概率增加到2/3。现在我们知道第三扇门有山羊,第二扇门有车的概率增加到2/3。因此,换门更有利。
## 导入库
import random
import matplotlib.pyplot as plt
## 初始化数据
# 1 = car
# 2 = goat
doors = ['goat','goat','car']switch_win_probability = []
stick_win_probability = []plt.axhline(y = 0.66666,color = 'r',linestyle='-')
plt.axhline(y = 0.33333,color = 'g',linestyle='-')
<matplotlib.lines.Line2D at 0x205f5578648>
import random
import matplotlib.pyplot as plt
## 初始化数据
# 1 = car
# 2 = goat
doors = ['goat','goat','car']switch_win_probability = []
stick_win_probability = []# monte carlo simulationdef monte_carlo(n):# calculating switch and stick wins:switch_wins = 0stick_wins = 0for i in range(n):# randomly placing the car and goats behind three doorsrandom.shuffle(doors)# contestant's choicek = random.randrange(2)# If the contestant doesn't get carif doors[k] != 'car':switch_wins += 1else:stick_wins += 1# updatating the list valuesswitch_win_probability.append(switch_wins/(i+1))stick_win_probability.append(stick_wins/(i+1))# plotting the dataplt.plot(switch_win_probability)plt.plot(stick_win_probability)# print the probability valuesprint('Winning probability if you always switch',switch_win_probability[-1])print('Winning probability if you always stick to your original choice:',stick_win_probability[-1])
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q0oAMCrF-1638621844579)(output_30_0.png)]
monte_carlo(1000)
plt.axhline(y = 0.66666,color = 'r',linestyle='-')
plt.axhline(y = 0.33333,color = 'g',linestyle='-')
Winning probability if you always switch 0.655
Winning probability if you always stick to your original choice: 0.345<matplotlib.lines.Line2D at 0x205f40976c8>
4、Buffon’s Needle问题
法国贵族Buffon,在1777年发布了以下问题:
假设我们在一张划线纸上扔一根短针——针头正好跨越线的位置的可能性是多大?
概率取决于纸上线条之间的距离(d),也取决于我们扔的针的长度(l),或者更确切地说,这取决于比率l/d。对于这个例子,我们可以认为针l ≤ d。简言之,我们的目的是假设针不能同时跨越两条不同的线。令人惊讶的是,这个问题的答案涉及PI。
import random
import matplotlib.pyplot as plt
import math
def monte_carlo(runs,needles,n_lenth,b_width):# Empty list to store pi values:pi_values = []# Horizontal line for actual value of PIplt.axhline(y=math.pi,color = 'r',linestyle='-')# For all runs:for i in range(runs):# Initialize number of hits as 0nhits = 0# For all needlesfor j in range(needles):# We will find the distance from the nearest vertical line# min = 0,max = b_width/2x = random.uniform(0,b_width/2.0)# The theta value will be from 0 to pi/2theta = random.uniform(0,math.pi/2)# checking if the needle crosses the line or notxtip = x - (n_lenth/2.0)*math.cos(theta)if xtip < 0 :nhits += 1# Going with the formulanumerator = 2.0 * n_lenth * needlesdenominator = b_width * nhits# Append the final value of pipi_values.append((numerator/denominator))# Final pi value after all iterationsprint(pi_values[-1])# Plotting the graph:plt.plot(pi_values)
# Total number of runs
runs = 100
# Total number of needles
needles = 100000
# Length of needle
n_lenth = 2
# space between 2 verical lines
b_width = 2
# Calling the main function
monte_carlo(runs,needles,n_lenth,b_width)
3.153728495513821
5、为什么庄家总是赢?
赌场如何赚钱?诀窍很简单 —— "你玩得越多, 赌场赚得越多。让我们通过一个简单的蒙特卡洛模拟示例来看看其运作原理。
考虑一个假想的游戏,玩家必须从一袋芯片中挑一个芯片。
规则:
- 袋子里装着1~100个芯片。
- 用户可以投注芯片数量为偶数或奇数。
- 在这个游戏中,10和11是特殊数字。如果我们押注于偶数,则 10 将计为奇数,如果我们押注奇数,则 11 将计为偶数。
- 如果我们押注偶数, 我们得到 10, 那么我们输了。
- 如果我们押注奇数, 我们得到 11, 那么我们输了。
如果我们押注奇数,我们获胜的概率为49/100。庄家获胜的概率是51/100。因此,对于一个奇数赌注,庄家的利润是 = 51/100- 49/100 = 200/10000 = 0.02 = 2%
如果我们押注于偶数,用户获胜的概率为 49/100。庄家获胜的概率是51/100。因此,对于一个偶数赌注,庄家的利润是 = 51/100-49/100 = 200/10000 = 0.02 = 2%
总之,每下1美元的赌注,其中0.02美元就归庄家的。相比之下,轮盘赌庄家的最低利润为2.5%。因此,我们确信,在假想的比赛中,你比轮盘赌更有可能获胜。
import random
import matplotlib.pyplot as plt# Place your bet:
# User can choose even or odd number
choice = input("Don you want to bet on Even number or odd number\n")# For even
if choice =='Even':def pickNote():# get random number between 1-100note = random.randint(1,100)# check for our game conditions# Notice that 10 isn't considered as even numberif note%2 != 0 or note == 10:return Falseelif note%2 ==0:return True# For odd
elif choice =='Odd':def pickNote():# get random number between 1-100note = random.randint(1,100)# check for our game conditions# Notice that 10 isn't considered as even numberif note%2 == 0 or note == 11:return Falseelif note%2 == 1:return True
Don you want to bet on Even number or odd number
Odd
# Main function
def play(total_money ,bet_money,total_plays):num_of_plays = []money = []# start with play number 1play = 1for play in range(total_plays):# Winif pickNote():# Add the money to our fundstotal_money = total_money + bet_money# append the play numbernum_of_plays.append(play)# append the new fund amoutmoney.append(total_money)# Loseif pickNote():# Add the money to our fundstotal_money = total_money - bet_money# append the play numbernum_of_plays.append(play)# append the new fund amoutmoney.append(total_money)# Plot the dataplt.ylabel('Player Money in $')plt.xlabel('Number of bets')plt.plot(num_of_plays,money)final_funds = []# Final values after all the iterationsfinal_funds.append(money[-1])return( final_funds)
# Run 10 time# 修改这里的次数
for i in range(1000):ending_fund = play(10000,100,50)
print(ending_fund)
print(sum(ending_fund))# print the money the player ends with
print('The player started with $10,000')
print('The player left with $',str(sum(ending_fund)/len(ending_fund)))
[10400]
10400
The player started with $10,000
The player left with $ 10400.0