蒙特卡洛仿真的基于Python实例

  • 文章原作者:新缸中之脑
  • 文章链接: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。如果我们重复掷这个硬币很多很多次,那么可以达到更高的准确性。

蒙特卡洛仿真的基于Python实例_第1张图片

## 导入库
import random 
import numpy as np
import matplotlib.pyplot as plt
## 投硬币的函数
def coin_filp():
    
    return random.randint(0,1) # 产生01随机数
## Monte Carlo Simulation

prob_list1 = [] # 空列表存储概率值

def monte_carlo(n):
    """
    n 是模拟次数
    """
    results = 0
    for i in range(n):
        flip_result = coin_filp()
        results =results + flip_result
        
        # Calculating probability value
        prob_value = results/(i+1)
        
        # append the probability values to the list
        prob_list1.append(prob_value)
        
        # plot the results
        plt.axhline(y = 0.5,color = 'red',linestyle='-')
        plt.xlabel('Iterations')
        plt.ylabel('Probability')
        plt.plot(prob_list1)
    
    return results/n
        
# calling the function

answer = monte_carlo(5000)
print('Final value:',answer)
Final value: 0.4968

蒙特卡洛仿真的基于Python实例_第2张图片

如上图所示,我们在 5000 次迭代后,获得正面向上的概率为 0.502。因此,这就是我们如何使用蒙特卡洛仿真来找到概率值的实验。

2.估计Π(pi)

蒙特卡洛仿真的基于Python实例_第3张图片

要估计 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 circle
        
        if (x**2+y**2>100**2):
            mypen.color('black')
            mypen.up()
            mypen.goto(x,y)
            mypen.down()
            mypen.dot()
            out_circle = out_circle + 1
        else:
            mypen.color('red')
            mypen.up()
            mypen.goto(x,y)
            mypen.down()
            mypen.dot()
            in_circle = in_circle + 1
            
        # calculating the value of PI
        pi = 4.0 * in_circle/(in_circle + out_circle)
        
        # append the values of PI in list
        pi_values.append(pi)
        
        # Calculating the errors
        avg_pi_errors = [abs(math.pi - pi) for pi in pi_values]
        
    # Print the final values of PI for each iterations
    print(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()

蒙特卡洛仿真的基于Python实例_第4张图片

plt.axhline(y = 0.0,color = 'g',linestyle='-')
plt.plot(avg_pi_errors)
plt.xlabel('Iterations')
plt.ylabel('Error')
plt.show()
    

蒙特卡洛仿真的基于Python实例_第5张图片

3.Monty Hall问题

假设在一个游戏节目中, 你可以选择三扇门之一: 一扇门后面是一辆车; 其他门后面都是山羊。你挑一扇门,比方说门1,主持人,他知道门后面是什么,打开另一扇门,比如说门3,有一只山羊。主持人然后问你:你是要坚持你的选择还是选择另一扇门?

换门对你有利吗?

根据概率,换门对我们是有利的。让我们了解一下:

最初,对于所有三个门,获得汽车的概率(P)是相同的(P = 1/3)。

蒙特卡洛仿真的基于Python实例_第6张图片

现在假设参赛者选择门 1。然后主持人打开第三扇门,门后面有一只山羊。接下来,主持人问参赛者是否想换门?

我们将看到为什么换门更有利:

蒙特卡洛仿真的基于Python实例_第7张图片

在上图中,我们可以看到,在主持人打开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='-')

蒙特卡洛仿真的基于Python实例_第8张图片

import random
import matplotlib.pyplot as plt
## 初始化数据
# 1 = car
# 2 = goat
doors = ['goat','goat','car']

switch_win_probability = []
stick_win_probability = []



# monte carlo simulation

def monte_carlo(n):

    # calculating switch and stick wins:
    switch_wins = 0
    stick_wins = 0

    for i in range(n):
        # randomly placing the car and goats behind three doors
        random.shuffle(doors)

        # contestant's choice
        k = random.randrange(2)

        # If the contestant doesn't get car
        if doors[k] != 'car':
            switch_wins += 1
        else:
            stick_wins += 1

        # updatating the list values
        switch_win_probability.append(switch_wins/(i+1))
        stick_win_probability.append(stick_wins/(i+1))
        
        # plotting the data
        plt.plot(switch_win_probability)
        plt.plot(stick_win_probability)
        
    # print the probability values
    print('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






蒙特卡洛仿真的基于Python实例_第9张图片

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 PI
    plt.axhline(y=math.pi,color = 'r',linestyle='-')

    # For all runs:
    for i in range(runs):
        # Initialize number of hits as 0
        nhits = 0

        # For all needles
        for j in range(needles):
            # We will find the distance from the nearest vertical line
            # min = 0,max = b_width/2
            x = random.uniform(0,b_width/2.0)
            # The theta value will be from 0 to pi/2
            theta = random.uniform(0,math.pi/2)
            
            # checking if the needle crosses the line or not
            xtip = x - (n_lenth/2.0)*math.cos(theta)
            if xtip < 0 :
                nhits += 1
        # Going with the formula
        numerator = 2.0 * n_lenth * needles
        denominator = b_width * nhits
        
        # Append the final value of pi
        pi_values.append((numerator/denominator))
        
    # Final pi value after all iterations
    print(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

蒙特卡洛仿真的基于Python实例_第10张图片

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-100
        note = random.randint(1,100)

        # check for our game conditions
        # Notice that 10 isn't considered as even number
        if note%2 != 0 or note == 10:
            return False
        elif note%2 ==0:
            return True
    
# For odd
elif choice =='Odd':
    def pickNote():
        # get random number between 1-100
        note = random.randint(1,100)

        # check for our game conditions
        # Notice that 10 isn't considered as even number
        if note%2 == 0 or note == 11:
            return False
        elif 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 1
    play = 1
    
    for play in range(total_plays):
        # Win
        if pickNote():
            # Add the money to our funds
            total_money = total_money + bet_money
            # append the play number
            num_of_plays.append(play)
            # append the new fund amout
            money.append(total_money)
        # Lose
        if pickNote():
            # Add the money to our funds
            total_money = total_money - bet_money
            # append the play number
            num_of_plays.append(play)
            # append the new fund amout
            money.append(total_money)
        # Plot the data
    plt.ylabel('Player Money in $')
    plt.xlabel('Number of bets')
    plt.plot(num_of_plays,money)
    final_funds = []
        # Final values after all the iterations
    final_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

蒙特卡洛仿真的基于Python实例_第11张图片

你可能感兴趣的:(机器学习,python,开发语言,后端)