Автоматизируйте скучные вещи - полосы монет - PullRequest
1 голос
/ 12 марта 2020

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

Задача состоит в том, чтобы собрать 10.000 выборок по 100 сальто каждый, а затем вычислить вероятность 6-кратной полосы головы или хвоста по всем выборкам - насколько я понимаю. Но в предыдущих вопросах проблема кодирования была описана как нечеткая. Поэтому, если бы вы, ребята, могли просто указать на ошибки в коде, это было бы неплохо:)

Я старался быть как можно более ленивым, что привело к тому, что мой macbook работал очень усердно. Это мой код Есть ли у меня проблема с первой итерацией сравнения текущего значения со значением ранее (насколько я понимаю, я бы сравнил индекс -1 (который тогда является индексом 100?) С текущим?)

import random

#variable declaration

numberOfStreaks = 0
CoinFlip = []
streak = 0

for experimentNumber in range(10000):
    # Code that creates a list of 100 'heads' or 'tails' values.
    for i in range(100):
        CoinFlip.append(random.randint(0,1))
    #does not matter if it is 0 or 1, H or T, peas or lentils. I am going to check if there is multiple 0 or 1 in a row        

    # Code that checks if there is a streak of 6 heads or tails in a row.
    for i in range(len(CoinFlip)):
        if CoinFlip[i] == CoinFlip[i-1]:  #checks if current list item is the same as before
            streak += 1 
        else:
            streak = 0

        if streak == 6:
            numberOfStreaks += 1

print('Chance of streak: %s%%' % (numberOfStreaks / 100))

Где я сделал беспорядок? Я не могу этого увидеть!

Ответы [ 5 ]

1 голос
/ 26 апреля 2020

Я начал гораздо сложнее, и теперь, увидев ваш код, я думаю, что не смог придумать более сложную "логи c" :)

Не смог найти рабочую идею для написания вторая часть!

import random

number_of_streaks = 0
coin_flips = []
streak = 0

for experiment_number in range (10000):
    # Code that creates a list of 100 'heads' and 'tails' values

def coin(coin_fl):  # Transform list into plain H or T
    for i in coin_flips[:-1]:
        print(i + ' ', end = '')

for i in range(100):    # Generates a 100 coin tosses
    if random.randint(0, 1) == 0:
        coin_head = 'H'
        coin_flips = coin_flips + [coin_head]
    else:
        coin_tail = 'T'
        coin_flips = coin_flips + [coin_tail]

coin(coin_flips)
1 голос
/ 07 апреля 2020

Я не смог прокомментировать ответ Стюарта, потому что недавно присоединился и у меня нет репутации, поэтому этот ответ сам по себе. Я новичок в программировании, поэтому, пожалуйста, поправьте меня, если я ошибаюсь. Я просто работал над той же проблемой в моем собственном учебном процессе.

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

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

Например, 5/100 = .05 -> .05 * 100 = 5%

Поэтому я добавил функцию, которая преобразует десятичное число в процент и округляет его до 4 десятичных знаков.

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

    import random

    #variables
    n_runs = 10000
    flips_per_run = 100
    total_instances = n_runs * flips_per_run
    coinFlip = []
    streak = 0
    numberOfStreaks = 0

    for experimentNumber in range(n_runs):
        # Code that creates a list of 100 'heads' or 'tails' values.'
        for i in range(flips_per_run):
            coinFlip.append(random.randint(0,1))
            if i==0:
                pass
            elif coinFlip[i] == coinFlip[i-1]:
                streak += 1
            else: 
                streak = 0

            if streak == 6:
                numberOfStreaks += 1

        coinFlip = []

    #calculation for chance as a decimal    
    chance = (numberOfStreaks / total_instances)
    #function that converts decimal to percent and rounds
    def to_percent(decimal):
        return round(decimal * 100,4)
    #function call to convert result
    chance_percent = to_percent(chance)
    #print result 
    print('Chance of streak: %s%%' % chance_percent)

Вывод: вероятность возникновения полосы: 0,7834%, а не .007834 %

1 голос
/ 12 марта 2020

Вам необходимо сбросить список CoinFlip. Ваша текущая программа просто продолжает добавляться в CoinFlip, что делает список очень длинным. Вот почему ваша производительность не очень хорошая. Я также добавил проверку для i == 0, чтобы вы не сравнивали ее с концом списка, потому что это технически не является частью серии.

for experimentNumber in range(10000):
    # Code that creates a list of 100 'heads' or 'tails' values.
    for i in range(100):
        CoinFlip.append(random.randint(0,1))
    #does not matter if it is 0 or 1, H or T, peas or lentils. I am going to check if there is multiple 0 or 1 in a row

    # Code that checks if there is a streak of 6 heads or tails in a row.
    for i in range(len(CoinFlip)):
        if i==0:
            pass
        elif CoinFlip[i] == CoinFlip[i-1]:  #checks if current list item is the same as before
            streak += 1
        else:
            streak = 0

        if streak == 6:
            numberOfStreaks += 1

    CoinFlip = []

print('Chance of streak: %s%%' % (numberOfStreaks / (100*10000)))

Я также думаю, что вам нужно разделить на 100 * 10000, чтобы получить реальную вероятность. Я не уверен, почему их "подсказка" предлагает разделить только на 100.

0 голосов
/ 08 мая 2020

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

Я пометил модификации с комментариями с префиксом #### и пронумеровал их со ссылкой на пояснения, которые следуют ниже. .

import random

#variable declaration

numberOfStreaks = 0

for experimentNumber in range(10000):
    # Code that creates a list of 100 'heads' or 'tails' values.
    CoinFlip = [] #### (1) create a new, empty list for this list of 100
    for i in range(100):
        CoinFlip.append(random.randint(0,1))
    #does not matter if it is 0 or 1, H or T, peas or lentils. I am going to check if there is multiple 0 or 1 in a row        

    #### # (6) example / test
    #### # if uncommented should be 100%
    #### CoinFlip = [ 'H', 'H', 'H', 'H', 'H', 'H', 'T', 'T', 'T', 'T', 'T', 'T' ]

    # Code that checks if there is a streak of 6 heads or tails in a row.
    streak = 1 #### (2, 4) any flip is a streak of (at least) 1; reset for next check
    for i in range(1, len(CoinFlip)): #### (3) start at the second flip, as we will look back 1
        if CoinFlip[i] == CoinFlip[i-1]:  #checks if current list item is the same as before
            streak += 1
        else:
            streak = 1 #### (2) any flip is a streak of (at least) 1

        if streak == 6:
            numberOfStreaks += 1
            break #### (5) we've found a streak in this CoinFlip list, skip to next experiment
                  #### if we don't, we get percentages above 100, e.g. the example / test above
                  #### this makes some sense, but is likely not what the book's author intends

print('Chance of streak: %s%%' % (numberOfStreaks / 100.0))

Объяснение этих изменений

Ниже приводится краткое объяснение этих изменений. Каждый из них в значительной степени независим, исправляя различные проблемы с кодом.

  1. очистка / создание списка CoinFlip в начале каждого эксперимента
    • без этого новые элементы добавил в список из предыдущего эксперимента
  2. подтверждение того, что любой переворот, даже один 'H' или 'T' (или 1 или 0 ), представляет полосу 1
    • без этого изменения, код фактически требует шести последовательных совпадений с первоначальным броском монеты, в общей сложности семь (немного менее интуитивное альтернативное изменение будет заменой if streak == 6: на if streak == 5:)
  3. начиная проверку со второго броска, используя range(1, len(CoinFlip)) (списки nb нумерованы нулями)
    • , когда код просматривает список , for l oop с range(), начинающимся с 0, будет некорректно сравнивать индекс 0 с индексом -1 ( последний элемент списка )
  4. (перемещение прицела и) сброс Счетчик streak перед каждой проверкой
    • без этого изменения начальная полоса в эксперименте может быть добавлена ​​к частичной полосе из предыдущего эксперимента (см. Проверка кода для предлагаемой демонстрации)
  5. при выходе из чека, как только мы обнаружили полосу

Этот вопрос в книге несколько плохо определен, и заключительная часть может быть истолкована как означающая "проверьте, если [хотя бы?] a [холост?] найдена полоса [точно?] шесть [или больше?] найдено ". Это решение интерпретирует check как булеву оценку (т. Е. Мы только фиксируем, что этот список содержал полосу или нет), и интерпретирует a не исключительно (т.е. мы допускаем более длинные полосы) или несколько полос для подсчета; как было верно в коде, представленном в вопросе).

(Необязательно 6.) Тестирование кода

Пример с комментариями / «Тест» позволяет переключать обычно генерируемые случайным образом сальто на одно и то же известное значение в каждом эксперименте. В этом случае фиксированный список, который должен рассчитываться как 100%. Если вы не согласны с интерпретацией спецификации задачи и отключите выход проверки, описанной в (5.), вы можете ожидать, что программа выдаст 200%, поскольку в каждом эксперименте есть две четкие полосы по шесть. Отключение break в сочетании с этим вводом сообщает точно, что.

Вы должны всегда использовать этот тип техники (использовать известный ввод, проверять вывод), чтобы убедить себя, что код работает или не работает так, как он утверждает или как вы ожидаете.

Фиксированный ввод CoinFlip = [ 'H', 'H', 'H', 'H', 'T', 'T', 'T' ] может быть использован для выделения проблемы, решаемой с помощью (4.). В случае возврата код вычислит процент экспериментов (все с этим вводом), содержащих полосу из шести последовательных H или T как 50%. Хотя (5.) устраняет независимую проблему, удаление добавленного break еще больше усугубляет ошибку и повышает рассчитанный процент до 99,99%. Для этого ввода рассчитанный процент, содержащий полосу шести, должен составлять 0%.

Вы найдете полный код, как показано здесь, дает оценки около 80%. Это может быть удивительно, но автор книги намекает, что это может иметь место:

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

- Аль Свейгарт, Полосы с перевернутыми монетами

Можно также рассмотреть дополнительные источники. WolframAlpha рассчитывает, что шанс получить "полосу из 6 голов за 100 подбрасываний монет" составляет примерно 1 за 2 . Здесь мы оцениваем вероятность получения полосы из 6 ( или более ) голов или полосы из шести ( или более ) хвостов, что можно ожидать быть еще более вероятным. В качестве более простого, независимого примера этого кумулятивного эффекта: предположим, что вероятность забрать сердце из обычной колоды игральных карт составляет 13 из 52, а взять сердце или алмаз - 26 из 52.


Примечания к расчету

Может также помочь понять, что автор также использует ярлык для вычисления процента. Это может сбить с толку новичков, смотрящих на окончательный расчет.

Напомним, рассчитывается процент:

\frac{x}{total}\times100

Мы знаем, что всего количество экспериментов, которые нужно запустить, будет 10000

\frac{x}{10000}\times100

Поэтому

\frac{x}{10000}\times100=\frac{100x}{10000}=\frac{x}{100}

Постскриптум: Я позволил себе сменить 100 на 100.0 в последней строке. Это позволяет коду правильно рассчитать процент в Python 2. Это не требуется для Python 3, как указано в вопросе и книге.

0 голосов
/ 24 апреля 2020
import random
numStreaks = 0
test = 0
flip = []

#running the experiment 10000 times

for exp in range(10000):
    for i in range(100): #list of 100 random heads/tails

        if random.randint(0,1) == 0:
            flip.append('H')
        else:
            flip.append('T')

    for j in range(100): #checking for streaks of 6 heads/tails

        if flip[j:j+6] == ['H','H','H','H','H','H']:
            numStreaks += 1
        elif flip[j:j+6] == ['T','T','T','T','T','T']:
            numStreaks += 1
        else:
            test += 1 #just to test the prog
            continue
print (test)
chance = numStreaks / 10000
print("chance of streaks of 6: %s %%" % chance )
...