我想模拟 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
我想模拟 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
这里有点数学。
普通骰子将以相等的概率给每个数字 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)
。
如果您查看wikipedia entry,您会发现在这种情况下,累积概率函数将不是由 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))
更多语言不可知,但您可以使用查找表。
使用 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
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
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中的每个条目相关联的概率”,其中anp.range(N)
代表我们。“如果没有给出样本,则假设在a中的所有条目上均匀分布。”
对于具有不同概率的随机对象,请参阅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
干杯
——丹尼斯
只是为了提出一种更有效(和 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
在没有 Python 3 累积的情况下,可以编写一个简单的循环来计算累积和。
from random import random
biases = [0.0,0.3,0.5,0.99]
coins = [1 if random()<bias else 0 for bias in biases]
我为字典创建了一个代码,给出了一个事件和相应的概率,它返回了相应的键,即那个概率的事件。
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
我们也可以使用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
如果您想多次滚动有偏差的骰子(具有给定的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]
对于 python 3.6 及更高版本,您可以使用已经是 stdlib 一部分的随机选择()方法。要在您的示例中模拟模具,等效代码将是:-
import random
def roll(N, bias_list):
return random.choices(list(range(N)), weights=bias_list, k=1)[-1]