Попытка напечатать вероятность сброса - PullRequest
0 голосов
/ 25 сентября 2019

У меня есть код для продолжения цикла, пока не будет выполнен сброс.теперь я пытаюсь сделать так, чтобы я использовал счетчик, чтобы показать, сколько раздач было разложено, а затем разделить на одну, чтобы получить вероятность.

Для кода, который у меня есть, используя счетчик, он возвращает его как 0

from collections import namedtuple
from random import shuffle

Card = namedtuple("Card", "suit, rank")

class Deck:
    suits = '♦♥♠♣'
    ranks = '23456789JQKA'

    def __init__(self):
        self.cards = [Card(suit, rank) for suit in self.suits for rank in self.ranks]
        shuffle(self.cards)

    def deal(self, amount):
        return tuple(self.cards.pop() for _ in range(amount))

flush = False
count = 0
while not flush:

    deck = Deck()
    stop = False
    while len(deck.cards) > 5:
        hand = deck.deal(5)
        # (Card(suit='♣', rank='7'), Card(suit='♠', rank='2'), Card(suit='♥', rank='4'), Card(suit='♥', rank='K'), Card(suit='♣', rank='3'))

        if len(set(card.suit for card in hand)) > 1:
            #print(f"No Flush: {hand}")
            continue
        print(f"Yay, it's a Flush: {hand}")
        flush = True
        break
        if flush:
            break
        else:
            count +=1
print(f'Count is {count}')

Вверху немного больше кода, используемого для методов инициализации, если вам это тоже нужно, дайте мне знать

Ответы [ 2 ]

2 голосов
/ 25 сентября 2019

Я думаю, это должно сработать для вас.Хотя это зависит от того, как определяется ваш Deck().Я пытался оставить ваш код в том же состоянии, в каком вы его написали, но мне пришлось внести некоторые изменения, чтобы не было ошибок.Я также на самом деле не запускал его, поскольку у меня не определено Deck.

flush = False
count = 0
while not flush:

    deck = Deck()
    stop = False
    while len(deck.cards) > 5:
        hand = deck.deal(5)
        # (Card(suit='♣', rank='7'), Card(suit='♠', rank='2'), Card(suit='♥', rank='4'), Card(suit='♥', rank='K'), Card(suit='♣', rank='3'))

        if len(set(card.suit for card in hand)) > 1:
            print(f"No Flush: {hand}")
        else:
            print(f"Yay, it's a Flush: {hand}")
            flush = True
            break
        count +=1
print(f'Count is {count}')

Но это не даст вам вероятности получить флеш, и вы, честно говоря, вероятно, закончитекарточек в deck до того, как вы получите сброс почти в каждом запуске ...

Я бы подумал изменить код на этот, чтобы устранить некоторые избыточности.

flush = False
count = 0
while not flush:

    deck = Deck()
    while len(deck.cards) > 5:
        hand = deck.deal(5)
        # (Card(suit='♣', rank='7'), Card(suit='♠', rank='2'), Card(suit='♥', rank='4'), Card(suit='♥', rank='K'), Card(suit='♣', rank='3'))

        if len(set(card.suit for card in hand)) == 1:
            print(f"Yay, it's a Flush: {hand}")
            flush = True
            break
        else:
            print(f"No Flush: {hand}")
            count +=1
print(f'Count is {count}')
1 голос
/ 25 сентября 2019

Ваш код (и то, что доступно в ответе @ Мейсона) будет оценивать вероятность в конечном итоге получения вашего первого флеша.Чтобы оценить вероятность получения флеша в общем , что, как я полагаю, является тем, что вам нужно, вы должны провести этот эксперимент много тысяч раз.На практике это называется симуляцией Монте-Карло.

Примечание : Когда я начал узнавать о Монте-Карлосе, я подумал, что это что-то вроде «волшебной», таинственно сложной вещи ... в основном потому, что их имя звучит так экзотично.Не обманывайтесь.«Монте-Карло» - это просто чрезмерно причудливое и произвольное название для «симуляции».Они могут быть довольно элементарными.

Несмотря на это, симуляции являются своего рода волшебными, потому что вы можете использовать их, чтобы грубо заставить решение из сложной системы, даже когда трудно получить математическую модель этой системыпо.Скажем, к примеру, у вас нет четкого понимания математики комбинаций или перестановок - что даст точный ответ на ваш вопрос «Каковы шансы получить флеш?» .Мы можем запустить множество симуляций вашей карточной игры, чтобы выяснить, какова будет эта вероятность с высокой степенью достоверности.Я сделал это ниже (закомментировал части вашего исходного кода, которые не были нужны):

from collections import namedtuple
from random import shuffle
import pandas as pd

#%% What is the likelyhood of getting flush? Mathematical derivation
""" A flush consists of five cards which are all of the same suit.
We must remember that there are four suits each with a total of 13 cards.
Thus a flush is a combination of five cards from a total of 13 of the same suit.
This is done in C(13, 5) = 1287 ways.
Since there are four different suits, there are a total of 4 x 1287 = 5148 flushes possible. 
Some of these flushes have already been counted as higher ranked hands.
We must subtract the number of straight flushes and royal flushes from 5148 in order to
obtain flushes that are not of a higher rank.
There are 36 straight flushes and 4 royal flushes.
We must make sure not to double count these hands.
This means that there are 5148 – 40 = 5108 flushes that are not of a higher rank. 
We can now calculate the probability of a flush as 5108/2,598,960 = 0.1965%.
This probability is approximately 1/509. So in the long run, one out of every 509 hands is a flush."""
"SOURCE: https://www.thoughtco.com/probability-of-a-flush-3126591"

mathematically_derived_flush_probability = 5108/2598960 * 100

#%% What is the likelyhood of getting flush? Monte Carlo derivation

Card = namedtuple("Card", "suit, rank")

class Deck:
    suits = '♦♥♠♣'
    ranks = '23456789JQKA'

    def __init__(self):
        self.cards = [Card(suit, rank) for suit in self.suits for rank in self.ranks]
        shuffle(self.cards)

    def deal(self, amount):
        return tuple(self.cards.pop() for _ in range(amount))

#flush = False
hand_count = 0
flush_count = 0
flush_cutoff = 150 # Increase this number to run the simulation over more hands.
column_names = ['hand_count', 'flush_count', 'flush_probability', 'estimation_error']
hand_results = pd.DataFrame(columns=column_names)

while flush_count < flush_cutoff:
    deck = Deck()
    while len(deck.cards) > 5:
        hand_count +=1
        hand = deck.deal(5)
        # (Card(suit='♣', rank='7'), Card(suit='♠', rank='2'), Card(suit='♥', rank='4'), Card(suit='♥', rank='K'), Card(suit='♣', rank='3'))
        if len(set(card.suit for card in hand)) == 1:
#            print(f"Yay, it's a Flush: {hand}")
            flush_count +=1
#            break
#        else:
#            print(f"No Flush: {hand}")
        monte_carlo_derived_flush_probability = flush_count / hand_count * 100
        estimation_error = (monte_carlo_derived_flush_probability - mathematically_derived_flush_probability) / mathematically_derived_flush_probability * 100
        hand_df = pd.DataFrame([[hand_count,flush_count,monte_carlo_derived_flush_probability, estimation_error]], columns=column_names)
        hand_results = hand_results.append(hand_df)

#%% Analyze results
# Show how each consecutive hand helps us estimate the flush probability
hand_results.plot.line('hand_count','flush_probability').axhline(y=mathematically_derived_flush_probability,color='r')

# As the number of hands (experiments) increases, our estimation of the actual probability gets better.
# Below the error gets closer to 0 percent as the number of hands increases.
hand_results.plot.line('hand_count','estimation_error').axhline(y=0,color='black')

#%% Memory usage
print("Memory used to store all %s runs: %s megabytes" % (len(hand_results),round(hand_results.memory_usage(index=True,deep=True).sum()/1000000, 1)))

В данном конкретном случае, благодаря математике, мы могли бы просто уверенно получить вероятность полученияфлеш как 0.1965%.Чтобы доказать, что наша симуляция пришла к правильному ответу, мы можем сравнить ее результат после 80 000 раздач:

enter image description here

Как видите, наша симуляция flush_probability(синим цветом) приближается к математически полученной вероятности (черным цветом).

Аналогичным образом, ниже представлен график estimation_error между моделируемой вероятностью и математически полученным значением.Как вы можете видеть, ошибка оценки была более чем на 100% в ранних прогонах моделирования, но постепенно увеличивалась до 5% от ошибки.

enter image description here

Если бы вы запустили симуляцию, скажем, для удвоенного числа рук, то мы бы увидели, что синие и красные линии в конечном итоге пересекаются с черной горизонтальной линией на обеих диаграммах, что означает, что смоделированный ответ становится эквивалентнымна математически полученный ответ.

Для симуляции или не для симуляции?

Наконец, вы можете спросить:

"Если я могу сгенерировать точныйОтветьте на проблему, смоделировав ее, и зачем вообще беспокоиться обо всей сложной математике? "

Ответ, как и в случае практически любого решения в жизни, - компромисс".

В нашем примере мы могли запустить симуляцию на достаточном количестве рук, чтобы получить точный ответ с высокой степенью достоверности.Однако, если кто-то запускает симуляцию, потому что он не знает ответа (что часто бывает), тогда нужно ответить на другой вопрос,

«Как долго я запускаю симуляцию, чтобы быть уверенным, что у меня правильный ответ?»

Ответ на этот вопрос кажется простым:

"Запустите его на долгое время. "

В конечном итоге ваши расчетные результаты могут сходиться к одному значению, так что результаты дополнительных имитаций не будут сильно отличаться от предыдущих прогонов.Проблема здесь в том, что в некоторых случаях, в зависимости от сложности системы, которую вы моделируете, на первый взгляд конвергентный вывод может быть временным явлением.То есть, если вы запустили еще сто тысяч симуляций, вы можете начать видеть, что ваши результаты отличаются от того, что вы считали своим стабильным ответом.В другом сценарии, несмотря на запуск десятков миллионов симуляций, может случиться так, что результат все еще не сходится.У вас есть время для программирования и запуска симуляции?Или математическое приближение приведет вас туда раньше?

Есть еще одна проблема:

* «Какова стоимость?»

Потребительские компьютеры сегодня относительно дешевы, но 30 лет назад они стоили от 1083 * 4000 до 9000 в 2019 долларах.Для сравнения, TI89 стоил всего $ 215 (опять же, в 2019 долларах).Так что, если бы вы задавали этот вопрос еще в 1990 году и у вас была хорошая математика по вероятности, вы могли бы сэкономить 3800 долларов, используя TI89.Стоимость сегодня так же важна: моделирование самостоятельного вождения автомобилей и сворачивания белка может сжечь многие миллионы долларов.

Наконец, для критически важных приложений может потребоваться как симуляцияи математическая модель для перекрестной проверки результатов обоих подходов.Ярким примером этого является то, что Мэтт Паркер из StandUpMaths вычислил шансы посадки на любое свойство в игре «Монополия» путем моделирования и подтвердил эти результаты с помощью математической модели Ханны Фрай той же игры.

...