[英]Simple Monte Carlo Simulation in python
在您看到每个数字之前,您需要掷骰子的次数是多少?
我被要求定义一个运行蒙特卡罗模拟的函数,该函数返回上述问题的估计值。 我对解决方案的理解是,我需要:
我对编程和 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)
您可能没有打印函数返回的任何内容 - 这就是为什么它什么都不显示的原因。
使用print(roll())
而不是roll()
来打印你得到的结果。
您有太多循环,并且您的解决方案使用了太多内存空间。
考虑一下运气不好,必须滚动 1.000.000.000.000 次才能获得前 6 个 - 您将在列表中保存 1.000.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
您的while
条件并未表达您的期望。 你可能想使用列表理解
while any([x not in collection for x in [1, 2, 3, 4, 5, 6])
还有,你不希望3层循环,只有两个:一个for
每个审判和其他while
审判是不完整的。 一个工作示例,接近您的原始帖子是
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 len(sides_rolled) < 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.