Python实现蒙特卡洛模拟

蒙特卡洛模拟是一种统计学方法,基本原理是通过大量的随机样本对系统进行模拟,从而求得所需计算的参量。使用蒙特卡洛模拟方法的基本要素包括:构建或描述概率模型、从已知概率分布采样、建立各种估计量。

使用“简书-朱焕”的"定量分析项目总持续时间"例子:比如说我们现在有个项目,该项目共有三个WBS要素分别是设计、建造和测试,为了简单起见我们假设这三个WBS要素的预估的工期概率分布都呈标准正态分布,而且三者之间都是完成到开始的逻辑关系,这样整个项目工期就是这三个WBS要素工期之和。例子的详细情况参见[1]。

使用蒙特卡洛模拟方法,首先构建概率模型(这个应该是解决问题的关键),这个例子中假设了设计、建造和测试三个要素呈正态分布;然后根据正态分布对这三个要素进行采样;估计量就是工期时间,工期时间是三个要素之和,根据采样结果计算工期的模拟值,并计算工期模拟值的出现频率(概率),最后根据出现频率计算累积概率。下面是Python代码:

import numpy as np
import matplotlib.pyplot as plt
import math

# 参数
mu = [14, 23, 22]
sigma = [2, 3, 4]
tips = ['design', 'build', 'test']

figureIndex = 0
fig = plt.figure(figureIndex, figsize=(10,8))
# 显示分布图
color = ['r', 'g', 'b']
ax = fig.add_subplot(111)
#ax = plt.subplot(1,1,1)

for i in range(3):
    # 参考https://www.jb51.net/article/146073.htm.[2]
    x = np.linspace(mu[i] - 3 * sigma[i], mu[i] + 3 * sigma[i], 100)
    y_sig = np.exp(-(x - mu[i]) ** 2 / (2 * sigma[i] ** 2)) / (math.sqrt(2 * math.pi) * sigma[i])
    ax.plot(x, y_sig, color[i]+'-', linewidth=2, alpha=0.6, label=tips[i])
    #
ax.legend(loc='best', frameon=False)
ax.set_xlabel('# of days')
ax.set_ylabel('probability')
plt.grid(True)

# 蒙特卡洛采样
# 三个WBS要素
size = 10000
samples = [np.random.normal(mu[i], sigma[i], size) for i in range(3)]
# 计算工期
data = np.zeros(len(samples[1]))
for i in range(len(samples[1])):
    for j in range(3):
        data[i] += samples[j][i]
    data[i] = int(data[i])

# 统计一个列表中每个元素出现的次数
# 参考https://blog.csdn.net/qq_42467563/article/details/86182266.[3]
def count(lis):
    lis=np.array(lis)
    key=np.unique(lis)
    x = []
    y = []
    for k in key:
        mask =(lis == k)
        list_new=lis[mask]
        v=list_new.size
        x.append(k)
        y.append(v)
    return x,y
#

# 计算工期出现频率与累积概率
a,b = count(data)
pdf = [x/size for x in b]

cdf = np.zeros(len(a))
for i in range(len(a)):
    if i > 0:
        cdf[i] += cdf[i-1]
    cdf[i] += b[i]

cdf = cdf/size

figureIndex += 1
fig = plt.figure(figureIndex, figsize=(10,8))
ax = fig.add_subplot(211)
ax.bar(a, height=pdf, color = 'blue',edgecolor = 'white', label='MC PDF')
ax.plot(a, pdf)
ax.legend(loc='best', frameon=False)
ax.set_xlabel('# of days for project')
ax.set_ylabel('probability')
ax.set_title('Monte Carlo Simulation')

ax = fig.add_subplot(212)
ax.plot(a, cdf, 'r-', marker='o', mfc='b', ms=4, lw=2, alpha=0.6, label='MC CDF')
ax.legend(loc='best', frameon=False)
ax.set_xlabel('# of days for project')
ax.set_ylabel('probability')
ax.grid(True)

plt.show()

模拟结果:

蒙特卡洛模拟结果

参考资料:

[1] 朱焕, “蒙特卡洛模拟(Monte Carlo Simulation)浅析”, https://www.jianshu.com/p/cb44f4b457c3.

[2] 脚本之家, “Python使用numpy产生正态分布随机数的向量或矩阵操作示例”, https://www.jb51.net/article/146073.htm.

[3] 三尺秋水一点飞鸿, “Python统计一个列表中每个元素出现的次数。四种方法,总有一款适合你”, https://blog.csdn.net/qq_42467563/article/details/86182266.

  • 27
    点赞
  • 207
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蒙特卡洛模拟是一种基于概率的模拟方法,可以用来解决在非确定性模型中难以进行分析的问题。在Python中,可以使用随机数生成算法来实现蒙特卡洛模拟。 一个经典的蒙特卡洛模拟的实例是计算圆周率π的近似值。通过在一个正方形内随机生成大量的点,并统计落在圆内的点的比例,可以利用这个比例来估计圆的面积,从而得到π的近似值。 以下是一个简单的Python实例代码,用于进行蒙特卡洛模拟计算π的近似值: ```python import random def monte_carlo_pi(num_points): points_inside_circle = 0 points_total = 0 for _ in range(num_points): x = random.uniform(-1, 1) y = random.uniform(-1, 1) distance = x**2 + y**2 if distance <= 1: points_inside_circle += 1 points_total += 1 pi_approximation = 4 * points_inside_circle / points_total return pi_approximation # 调用函数进行蒙特卡洛模拟计算π的近似值 approx_pi = monte_carlo_pi(1000000) print(approx_pi) ``` 在这个例子中,我们使用了Python的random模块来生成随机数。通过生成大量的随机点,并计算落在圆内的点的比例,最后乘以4,我们可以得到π的近似值。 请注意,这个例子只是蒙特卡洛模拟的一个简单示例,实际应用中可能涉及更复杂的问题和算法。 #### 引用[.reference_title] - *1* *2* *3* [【Python蒙特卡洛模拟 | PRNG 伪随机数发生器 | 马特赛特旋转算法 | LCG 线性同余算法 | Python Random ...](https://blog.csdn.net/weixin_50502862/article/details/126732514)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值