Как выполнить правило умножения для выбора двух предметов без замены? - PullRequest
0 голосов
/ 14 января 2019

Я экспериментирую с sympy, чтобы воспроизвести пример, где в коробке есть три шарика:

  • красный
  • белый
  • синий

Два шарика будут вытянуты наугад без замены.

В: Какова вероятность получения красного мрамора, а затем белого мрамора?

Мне удалось рассчитать это с помощью правила умножения с помощью жесткого кодирования 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?

Ответы [ 2 ]

0 голосов
/ 25 января 2019

Я думаю, что вы используете правильно 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 каждого шага, разрешить неравномерное распределение вероятностей и т. Д.

0 голосов
/ 25 января 2019

В этом случае вам лучше использовать комбинированные функции.

Кажется, что 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)

Для N из M вещей вы можете просто сделать, как показано ниже

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...