我正在尝试使用sympy来重现一个盒子包含三个弹珠的示例:
将随机绘制两颗弹珠,而无需替换。
问:先绘制红色大理石然后再绘制白色大理石的机会是什么?
我已经能够使用乘法规则通过 hard-coding P()实例来计算此值,这些实例包装在选择第一个大理石之前的初始分布,然后在选择第二个大理石之前的分布:
from sympy.stats import DiscreteUniform, density, P
from sympy import symbols, Eq
# Coloured marbles
R, W, B = symbols('R W B')
# Select first marble without replacement
PFirstSelection = P(Eq(DiscreteUniform('FirstSeletion', (R, W, B)), R))
# Select second marble - Red is not longer available because it was selected without replacement
PSecondSelection = P(Eq(DiscreteUniform('SecondSelection', (W, B) ), W))
print(PFirstSelection)
# 1/3
print(PSecondSelection)
# 1/2
# Multiplication rule
print(PFirstSelection * PSecondSelection)
# 1/6
有没有更好的方法可以通过sympy实现这一目标?
答案 0 :(得分:1)
在这种情况下,您最好使用组合功能。
DiscreteUniform似乎不适合在创建后更改元素。
from sympy.functions.combinatorial.numbers import nC, nP
print(1 / nP(3, 2)) # 1/6
如果您不关心订单,
print(nP(2, 2) / nP(3, 2)) # 1/3
已编辑。 (并且还针对python3进行了修改)
对于M个事物中的N个,您只需执行以下操作即可
from sympy.functions.combinatorial.numbers import nC, nP
def pickProb(candidates, picks, ordered=False):
picks_num = len(picks)
numerator = nP(picks_num, picks_num) if ordered else 1
denominator = nP(len(candidates), picks_num)
return numerator / denominator
print(pickProb('RWB', 'RW')) # 1/6
print(pickProb('RWBrwba', 'Ra')) # 1/42
print(pickProb('RWBrwba', 'RWa')) # 1/210
print(pickProb('RWBrwba', 'RWa', ordered=True)) # 1/35
并且组合功能还可以处理重复项,例如'R','R','W','B'。
from operator import mul
from sympy.functions.combinatorial.numbers import nC, nP
def pickProb(candidates, picks):
picks_num = len(picks)
c_counts = {}
for c in candidates:
c_counts[c] = c_counts[c] + 1 if c in c_counts else 1
p_counts = {}
for p in picks:
p_counts[p] = p_counts[p] + 1 if p in p_counts else 1
combinations = reduce(mul, [nP(c_counts[x], p_counts[x]) for x in p_counts.keys()], 1)
denominator = nP(len(candidates), picks_num) / combinations
return 1 / denominator
print(pickProb('RWBra', 'RWa')) # 1/60
print(pickProb('RRRWa', 'RWa')) # 1/20
print(pickProb('RRRWa', 'RRa')) # 1/10
但是DiscreteUniform
不能,因为这种情况不是“统一的”。
from sympy.stats import DiscreteUniform, density, P, Hypergeometric
from sympy import Symbol, Eq
deck = DiscreteUniform('M', 'RRWB')
print(density(deck).dict) # {W: 1/4, R: 1/4, B: 1/4}
print(P(Eq(deck, Symbol('R')))) # 1/4
答案 1 :(得分:1)
我认为您使用的是正确的sympy,但是您可以改善使用python的方式(例如,更通用,更实用,更通用,没有硬编码)。
例如:
from sympy.stats import DiscreteUniform, density, P
from sympy import symbols, Eq
from itertools import accumulate
def ToSet(value):
return set(value.split(' '))
def ProbaOfPick(pickSet, fromSet, operationTag):
return P(Eq(DiscreteUniform(operationTag, symbols(fromSet)), symbols(pickSet)))
def PickWithoutReplacement(allset, picklist, probaFunc):
currentSet = allset
probaSeq = []
operationSeq = []
for pick in picklist:
operationTag = "picking: " + pick
newP = probaFunc(pick, currentSet, operationTag)
operationSeq.append(operationTag + " from " + str(currentSet))
probaSeq.append(newP)
currentSet -= set(pick)
return (operationSeq, probaSeq)
allset = ToSet('R W B Y Ma G1 G2')
picks = 'R', 'W', 'G2'
operationSeq, probaSeq = PickWithoutReplacement(allset, picks, ProbaOfPick)
probas = list(accumulate(probaSeq, lambda a, b: a*b))
for op in operationSeq:
print(op)
print(probas)
您还可以将均匀分布更改为任何非均匀分布。
编辑:添加了依赖项注入(ProbaOfPick
-> probaFunc
)。
此代码只是入门。
结果:
picking: R from {'G2', 'Ma', 'Y', 'B', 'R', 'G1', 'W'}
picking: W from {'G2', 'Ma', 'Y', 'B', 'G1', 'W'}
picking: G2 from {'G2', 'Ma', 'Y', 'B', 'G1'}
[1/7, 1/42, 1/210]
下一步:允许每个步骤选择1个以上,允许非均匀概率分布等