社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

python中的简单monte carlo模拟

Adam • 5 年前 • 2171 次点击  

你需要多少次掷骰子直到你看到每一个数字?

我被要求定义一个函数来运行蒙特卡罗模拟,该模拟返回上述问题的估计值。我对解决方案的理解是,我需要:

  1. 定义一个以试验次数为输入的函数
  2. 生成1到6之间的随机整数(模具上的边数)
  3. 如果该整数不在列表中,则将其存储在列表中
  4. 计算达到所述条件所需的试验次数,并返回该计数

我对编程,特别是python还比较陌生,所以我很难确定为什么在调用函数时我的语法不产生输出,我希望有人能帮助我朝着正确的方向前进

这是我的代码:

def roll(n=1000):
    trials = []
    sides = 6
    start = 1

    for i in range (n):
        for x in range (sides):
            collection = [random.randint(1,sides)]
            while any([x not in collection]):
            collection.append(random.randint(1,6))
            trials.append(len(collection))

    return sum(trials)/ len(trials)
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/42983
 
2171 次点击  
文章 [ 3 ]  |  最新文章 5 年前
Ralf
Reply   •   1 楼
Ralf    6 年前

通过使用 set 而不是一个列表,还可以更改迭代逻辑:

import random

def roll_till_all_sides_appeared():
    sides_seen = set()
    n = 0

    while len(sides_seen) < 6:
        side = random.randint(1, 6)
        sides_seen.add(side)         # will only be added if it isn't present
        n += 1

    return n

def test(repetitions):
    max_n = float('-inf')
    min_n = float('inf')
    sum_n = 0

    for _ in range(repetitions):
        n = roll_till_all_sides_appeared()
        max_n = max(max_n, n)
        min_n = min(min_n, n)
        sum_n += n

    print('max:', max_n)
    print('min:', min_n)
    print('avg:', sum_n / repetitions)

此代码可以如下使用:

>>> test(10)
max: 32
min: 8
avg: 14.3
>>> test(100)
max: 45
min: 6
avg: 14.13
>>> test(1000)
max: 56
min: 6
avg: 14.749
>>> test(10000)
max: 62
min: 6
avg: 14.6422
Jatentaki
Reply   •   2 楼
Jatentaki    6 年前

你的 while 条件不能表达你所期望的。你可能想用列表理解

while any([x not in collection for x in [1, 2, 3, 4, 5, 6])

另外,你不需要三层循环,只需要两层:一层 for 每次审判 虽然 审判尚未完成。一个有效的例子,接近你原来的职位

 import random

 def roll(n=1000):
     trials = []
     sides = 6
     start = 1
     possible_sides = [1, 2, 3, 4, 5, 6]

     for i in range (n):
         collection = [random.randint(1,sides)]
         while any([side not in collection for side in possible_sides]):
             collection.append(random.randint(1,6))
         trials.append(len(collection))

     return sum(trials)/ len(trials)

而更有效的解决方案 set 有效地执行与以前的解决方案相同的操作 any([side not in collection for side in possible_sides]) :

import random

 def roll(n=1000):
     trials = []
     sides = 6
     start = 1
     possible_sides = set([1, 2, 3, 4, 5, 6])

     for i in range (n):
         n_rolls = 0
         sides_rolled = set()
         while not sides_rolled == possible_sides:
             sides_rolled.add(random.randint(1, sides))
             n_rolls += 1

         trials.append(n_rolls)

     return sum(trials)/ len(trials)

或者,更有效的是,检查一下 len(sides_rolled) < 6 ,正如帕特里克·阿特纳在回答中指出的那样。

Patrick Artner
Reply   •   3 楼
Patrick Artner    6 年前

你可能不是 印刷 不管函数返回什么-这就是为什么它什么都不显示。

使用 print(roll()) 而不是 roll() 打印得到的结果。

循环太多,解决方案占用的内存空间太大。

考虑一下运气不好,必须掷1.000.000.000.000次才能得到前6个-你将在列表中保存1.000.000.000个其他数字。那是很多记忆。


你可以用 set 要记住看到的数字和一个计数器来计算查找所有数据所需的时间:

def roll(sides=6, n=1000):
    """Tests 'n' times to roll all numbers from 1 to 'sides' randomly.
    Returns average tries needed to see all numbers over 'n' tries."""
    trials = []   # collects all sinly tried counters

    for _ in range(n):
        seen = set()   # empty, will only ever store 6 elements at most
        tried = 0      # how long did it take to find all 6?
        while len(seen) < sides:  # use sides here as well
            seen.add(random.randint(1,sides))
            tried += 1
        trials.append(tried)

    return sum(trials)/n


print(roll())  

输出(4次启动):

14.878

14.694

14.732

14.516