我如何在 python 中模拟有偏差的模具?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/479236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:12:25  来源:igfitidea点击:

How do I simulate biased die in python?

pythonnumpyprobability

提问by Pratik Deoghare

I want to simulate N-sided biased die?

我想模拟 N 面偏置模具?

def roll(N,bias):
     '''this function rolls N dimensional die with biasing provided'''
     # do something
     return result

>> N=6
>> bias=( 0.20,0.20,0.15,0.15,0.14,0.16,)
>> roll(N,bias)
   2

回答by Yuval Adam

A little bit of math here.

这里有一点数学。

A regular die will give each number 1-6 with equal probability, namely 1/6. This is referred to as uniform distribution(the discrete version of it, as opposed to the continuous version). Meaning that if Xis a random variable describing the result of a single role then X~U[1,6]- meaning Xis distributed equally against all possible results of the die roll, 1 through 6.

一个普通的骰子会给每个数字 1-6 的概率相等,即1/6。这被称为均匀分布(它的离散版本,与连续版本相反)。这意味着 ifX是一个随机变量,描述单个角色的结果,则X~U[1,6]- 意义X针对骰子的所有可能结果平均分配,1 到 6。

This is equal to choosing a number in [0,1)while dividing it into 6 sections: [0,1/6), [1/6,2/6), [2/6,3/6), [3/6,4/6), [4/6,5/6), [5/6,1).

这相当于在选择数目[0,1)而将其分成6个部分:[0,1/6)[1/6,2/6)[2/6,3/6)[3/6,4/6)[4/6,5/6)[5/6,1)

You are requesting a different distribution, which is biased. The easiest way to achieve this is to divide the section [0,1)to 6 parts depending on the bias you want. So in your case you would want to divide it into the following: [0,0.2), [0.2,0.4), [0.4,0.55), 0.55,0.7), [0.7,0.84), [0.84,1).

您正在请求不同的分布,这是有偏见的。实现这一目标的最简单方法是[0,1)根据您想要的偏差将部分分成6 个部分。因此,在您的情况下,您希望将其分为以下几部分: [0,0.2), [0.2,0.4), [0.4,0.55), 0.55,0.7), [0.7,0.84), [0.84,1)

If you take a look at the wikipedia entry, you will see that in this case, the cumulative probability function will not be composed of 6 equal-length parts but rather of 6 parts which differ in length according to the biasyou gave them. Same goes for the mass distribution.

如果您查看维基百科条目,您会发现在这种情况下,累积概率函数不会由 6 个等长的部分组成,而是由 6 个长度不同的部分组成,这些部分的长度根据您给它们的偏差而定。质量分布也是如此。

Back to the question, depending on the language you are using, translate this back to your die roll. In Python, here is a very sketchy, albeit working, example:

回到问题,根据您使用的语言,将其翻译回您的掷骰子。在 Python 中,这是一个非常粗略但有效的示例:

import random
sampleMassDist = (0.2, 0.1, 0.15, 0.15, 0.25, 0.15)
# assume sum of bias is 1
def roll(massDist):
    randRoll = random.random() # in [0,1]
    sum = 0
    result = 1
    for mass in massDist:
        sum += mass
        if randRoll < sum:
            return result
        result+=1

print(roll(sampleMassDist))

回答by Toon Krijthe

More language agnostic, but you could use a lookup table.

更多的语言不可知,但你可以使用查找表。

Use a random number in the range 0-1 and lookup the value in a table:

使用 0-1 范围内的随机数并在表中查找值:

0.00 - 0.20   1
0.20 - 0.40   2
0.40 - 0.55   3
0.55 - 0.70   4
0.70 - 0.84   5
0.84 - 1.00   6

回答by nosklo

import random

def roll(sides, bias_list):
    assert len(bias_list) == sides
    number = random.uniform(0, sum(bias_list))
    current = 0
    for i, bias in enumerate(bias_list):
        current += bias
        if number <= current:
            return i + 1

The bias will be proportional.

偏差将成正比。

>>> print roll(6, (0.20, 0.20, 0.15, 0.15, 0.14, 0.16))
6
>>> print roll(6, (0.20, 0.20, 0.15, 0.15, 0.14, 0.16))
2

Could use integers too (better):

也可以使用整数(更好):

>>> print roll(6, (10, 1, 1, 1, 1, 1))
5
>>> print roll(6, (10, 1, 1, 1, 1, 1))
1
>>> print roll(6, (10, 1, 1, 1, 1, 1))
1
>>> print roll(6, (10, 5, 5, 10, 4, 8))
2
>>> print roll(6, (1,) * 6)
4

回答by shrokmel

It is a little surprising that the np.random.choiceanswer hasn't been given here.

np.random.choice这里没有给出答案,这有点令人惊讶。

from numpy import random 
def roll(N,bias):
    '''this function rolls N dimensional die with biasing provided'''
    return random.choice(np.range(N),p=bias)

The p option gives "the probabilities associated with each entry in a", where ais np.range(N)for us. "If not given the sample assumes a uniform distribution over all entries in a".

该p选项使“与每一项目相关的概率一个,其中”一个np.range(N)我们。“如果没有给出,样本假设在一个”中的所有条目上均匀分布。

回答by denis

See the recipe for Walker's alias methodfor random objects with different probablities.
An example, strings A B C or D with probabilities .1 .2 .3 .4 --

请参阅Walker对具有不同概率的随机对象的别名方法的配方。
例如,字符串 ABC 或 D 的概率为 .1 .2 .3 .4 --

abcd = dict( A=1, D=4, C=3, B=2 )
  # keys can be any immutables: 2d points, colors, atoms ...
wrand = Walkerrandom( abcd.values(), abcd.keys() )
wrand.random()  # each call -> "A" "B" "C" or "D"
                # fast: 1 randint(), 1 uniform(), table lookup

cheers
-- denis

干杯
——丹尼斯

回答by Mapio

Just to suggest a more efficient (and pythonic3) solution, one can use bisectto search in the vector of accumulated values — that can moreover be precomputed and stored in the hope that subsequent calls to the function will refer to the same "bias" (to follow the question parlance).

只是为了提出一个更有效的(和 pythonic3)解决方案,可以使用bisect来搜索累积值的向量——而且可以预先计算和存储,希望随后对该函数的调用将引用相同的“偏差”(遵循问题的说法)。

from bisect import bisect
from itertools import accumulate
from random import uniform

def pick( amplitudes ):
    if pick.amplitudes != amplitudes:
        pick.dist = list( accumulate( amplitudes ) )
        pick.amplitudes = amplitudes
    return bisect( pick.dist, uniform( 0, pick.dist[ -1 ] ) )
pick.amplitudes = None

In absence of Python 3 accumulate, one can just write a simple loop to compute the cumulative sum.

在没有 Python 3 累加的情况下,我们可以编写一个简单的循环来计算累加和。

回答by edo liberty

from random import random
biases = [0.0,0.3,0.5,0.99]
coins = [1 if random()<bias else 0 for bias in biases]

回答by niksy

i have created a code for a dictionary giving a event and corresponding probability, it gives back the corresponding key ie the event of that probability.

我为字典创建了一个代码,给出了一个事件和相应的概率,它返回了相应的键,即该概率的事件。

import random


def WeightedDie(Probabilities):   


    high_p = 0   
    rand = random.uniform(0,1)

    for j,i in Probabilities.items():
        high_p = high_p + i
        if rand< high_p:
            return j

回答by Sandipan Dey

We could use numpy's multinomialdistribution too

我们也可以使用numpy'smultinomial分布

import numpy as np

bias = [0.10,0.10,0.15,0.15,0.14,0.16,0.05,0.06,0.04,0.05]   # a 10-sided biased die
np.where(np.random.multinomial(1, bias, size=1)[0]==1)[0][0]+1 # just 1 roll
# 4

If you want to roll the biased die (with the given biasprobabilities) for ntimes, use the following function

如果您想多次掷有偏差的骰子(具有给定的bias概率)n,请使用以下函数

def roll(probs, ntimes):   # roll a len(probs) sided biased die with bias probs for ntimes
   return np.apply_along_axis(lambda x: x.tolist().index(1)+1, 1, 
                       np.random.multinomial(1, bias,  size=10)).tolist()

roll(probs=bias, ntimes=10)    # 10 rolls
# [5, 6, 8, 4, 8, 3, 1, 5, 8, 6]