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

发布于 2024-07-12 21:41:02 字数 263 浏览 7 评论 0原文

我想模拟 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

I want to simulate N-sided biased die?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

微凉 2024-07-19 21:41:02

这里有一点数学知识。

常规骰子会以相同的概率给出每个数字 1-6,即 1/6。 这被称为均匀分布(它的离散版本,而不是连续版本)。 这意味着如果 X 是描述单个角色结果的随机变量,则 X~U[1,6] - 意味着 X 是分布式的同等地针对掷骰子的所有可能结果(1 到 6)。

这相当于在 [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)

您要求不同的分布,这是有偏见的。
实现此目的的最简单方法是根据您想要的偏差将 [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)

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

回到问题,根据您使用的语言,将其翻译回您的骰子。 在 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))

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 X is a random variable describing the result of a single role then X~U[1,6] - meaning X is distributed equally against all possible results of the die roll, 1 through 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).

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).

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 bias you gave them. Same goes for the mass distribution.

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:

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))
自由如风 2024-07-19 21:41:02
from random import random
biases = [0.0,0.3,0.5,0.99]
coins = [1 if random()<bias else 0 for bias in biases]
from random import random
biases = [0.0,0.3,0.5,0.99]
coins = [1 if random()<bias else 0 for bias in biases]
软的没边 2024-07-19 21:41:02

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

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

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
逆流 2024-07-19 21:41:02

我们也可以使用 numpy 的多项式分布

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

如果您想滚动有偏差的骰子(具有给定的偏差概率)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]

We could use numpy's multinomial distribution too

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 bias probabilities) for n times, use the following function

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]
青丝拂面 2024-07-19 21:41:02

对于 python 3.6 及更高版本,您可以使用 stdlib 中已经包含的 random's choice() 方法。
要模拟示例中的骰子,等效代码是:-

import random

def roll(N, bias_list):
   return random.choices(list(range(N)), weights=bias_list, k=1)[-1]

   

For python 3.6 and above, you can make use of random's choices() method already part of stdlib.
To simulate the die in your example, the equivalent code would be:-

import random

def roll(N, bias_list):
   return random.choices(list(range(N)), weights=bias_list, k=1)[-1]

   
青萝楚歌 2024-07-19 21:41:02

更多与语言无关,但您可以使用查找表。

使用 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

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.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
乞讨 2024-07-19 21:41:02
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

偏差将成比例。

>>> 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

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

>>> 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
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
久隐师 2024-07-19 21:41:02

有点令人惊讶的是 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)

p 选项给出“与a中每个条目相关的概率”,其中a对我们来说是np.range(N)。 “如果没有给出,则样本假定在a中的所有条目上均匀分布”。

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

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 a is np.range(N) for us. "If not given the sample assumes a uniform distribution over all entries in a".

蛮可爱 2024-07-19 21:41:02

请参阅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

欢呼
——丹尼斯

See the recipe for Walker's alias method for random objects with different probablities.
An example, strings A B C or D with probabilities .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

晨敛清荷 2024-07-19 21:41:02

只是为了建议一种更有效(和 pythonic3)的解决方案,可以使用 bisect< /a> 在累积值向量中进行搜索 - 此外,可以预先计算并存储该向量,希望对该函数的后续调用将引用相同的“偏差”(遵循问题用语)。

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

在没有 Python 3 累积的情况下,只需编写一个简单的循环来计算累积和。

Just to suggest a more efficient (and pythonic3) solution, one can use bisect to 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).

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文