是否有Pandas / Numpy实现Monty Hall问题而不循环?

时间:2019-07-19 06:16:59

标签: python pandas numpy

这更多是好奇心练习...

如果您还没有听说过The Monty Hall问题,请在出色的youtube video中进行解释。

我使用numpy在python中对其进行了仿真:

import numpy as np

num_games = 100000
options = np.arange(1, 4, 1)

stick_result = 0
switch_result = 0

for i in range(1, num_games + 1):
    winning_door = np.random.randint(1, 4)
    first_choice = np.random.randint(1, 4)

    if winning_door == first_choice:
        stick_success += 1

    # remove a door that isn't the winning_door or the first_choice 
    door_to_remove = np.random.choice(options[~np.isin(options, [winning_door, first_choice])])
    options_with_one_door_removed = options[~np.isin(options, door_to_remove)]

    # switch door to remaining option that isn't the first choice
    second_choice_after_switch = options_with_one_door_removed[~np.isin(options_with_one_door_removed, first_choice)]

    if winning_door == second_choice_after_switch:
        switch_result += 1

这是否可能没有for循环?到目前为止,这是我所拥有的,但是我不确定如何进行门开关。

import numpy as np

num_games = 100000
options = np.arange(1, 4, 1)

winning_door = np.random.randint(1, 4, num_games)
first_choice = np.random.randint(1, 4, num_games)

stick_successes = (winning_door == first_choice).sum()

# remove a door that isn't the winning_door or the first_choice
door_to_remove = ???
options_with_one_door_removed = ???

# switch door to remaining option that isn't the first choice
second_choice_after_switch = ???

switch_successes = (winning_door == second_choice_after_switch).sum()

您必须确定游戏节目主持人从游戏的每个实例(winning_doorfirst_choice阵列的每一行)上卸下的门,然后将first_choice切换到其余的门。)

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

您这里最大的问题是用遮罩对choice进行向量化。看起来可能像这样:

def take_masked_along_axis(arr, where, index, axis):
    """ Take the index'th non-masked element along each 1d slice along axis """
    assert where.dtype == bool
    assert index.shape[axis] == 1
    # np.searchsorted would be faster, but does not vectorize
    unmasked_index = (where.cumsum(axis=axis) > index).argmax(axis=axis)
    unmasked_index = np.expand_dims(unmasked_index, axis=axis)  # workaround for argmax having no keepdims
    return np.take_along_axis(arr, unmasked_index, axis=axis)


def random_choice_masked_along_axis(arr, where, axis):
    """ Like the above, but choose the indices via a uniform random number """
    assert where.dtype == bool
    index = np.random.sample(arr.shape[:axis] + (1,) + arr.shape[axis+1:]) * where.sum(axis=axis, keepdims=True)
    return take_masked_along_axis(arr, where, index, axis=axis)

使代码的第一部分类似

options_broadcast = np.broadcast_to(options, (3, num_games))
removable = (options != options_broadcast) & (options != options_broadcast)
door_to_remove = random_choice_masked_along_axis(options_broadcast, where=removable, axis=0)