【问题标题】:Automate the boring stuff - Coin flip streaks自动化无聊的东西 - 硬币翻转条纹
【发布时间】:2020-06-24 18:47:21
【问题描述】:

我知道现在有很多关于它的问题,即使是同一个问题,但我想我尝试了一些不同的方法。

任务是对 10000 个样本进行 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))

我在哪里弄得一团糟?我真的看不出来!

【问题讨论】:

  • 看起来不错。当您位于数组的开头时,请小心比较先前的值。这可能意味着您需要调整循环边界。我对在此类问题中追踪问题的建议是在进行过程中打印出部分结果,并手动计算出您期望得到的结果。使问题更小,例如实验次数 = 10(或 1),翻转次数 = 12,条纹长度 = 3。计算一步的所有结果,然后继续下一步。例如。构建所有实验,计算所有实验的所有条纹,在所有条纹中搜索所需的条纹长度。
  • 打破它总是一个好方法,感谢您的帮助!

标签: python-3.x statistics coin-flipping


【解决方案1】:

您需要重置 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 才能得到真正的概率。我不知道为什么他们的"hint" 建议只除以 100。

【讨论】:

  • 嘿伙计!感谢您的帮助,问题是重新初始化 CoinFlip。我也不知道“通过”的可能性。这是一件好事!
  • 我可能是错的,但我认为这个答案将计算条纹中的条纹。可能更像是滚动平均值。例如,如果您的 100 次翻转中有 7 次连续,那么您的 numberOfStreaks 将是 2?这不是概率,也不是频率(这实际上是这个程序可以证明两者之间的差异以及使这个问题实际上很难得到正确的原因)。我猜条纹数应该由模数 = 0 的条纹长度除以 6 的商来累加。
  • 您的程序可以通过简单的计算来检查。翻转任何六连胜的概率是 (1/2)^6 (即 3.125%)。在 100 次抛硬币的 10k 次试验后,您出现 6 条的频率应该非常接近这一点,这在问题中暗示了 10000 是一个足够大的样本量。
  • 或者不是用 6 和 mod = 0 的条纹长度除的商,而是在达到 6 时重新计算条纹长度。
【解决方案2】:

我无法对 Stuart 的回答发表评论,因为我最近加入并且没有声誉,所以这就是为什么它自己的答案。我是编程新手,所以如果我错了,请任何人纠正我。我只是在自己的学习过程中解决同样的问题。

首先,我不确定为什么在范围长度相同的情况下使用多个 for 循环,所以我将它们结合起来并继续得到相同的结果。

另外,我注意到最终计算以百分比形式显示,但未从原始计算转换为百分比。

例如,5/100 = .05 -> .05 * 100 = 5%

因此,我添加了一个将小数转换为百分比并将其四舍五入到小数点后四位的函数。

最后,将硬编码改为变量,显然没关系,只是为了解释我改变的东西。

    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% 而不是 0.007834%

【讨论】:

    【解决方案3】:
    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 )
    

    【讨论】:

    • 编程新手。尝试学习python - 自学。遇到这个问题,阅读“自动化无聊的东西”。我的解决方案 - 我大多得到 0 作为答案,但有时确实得到 8%、5% 等
    • 欢迎来到stackoverflow!很好的第一次尝试格式化你的代码,尝试将你的问题作为帖子的一部分而不是作为评论放置(例如,你可以编辑你的帖子)。 Here's more information to help craft a good question
    【解决方案4】:

    我开始的方式更复杂,现在看到你的代码,我想我无法想出更复杂的“逻辑”:)

    找不到编写第二部分的可行想法!

    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)
    

    【讨论】:

      【解决方案5】:

      以下是对最初提供的代码的一组细微修改,可正确计算估计值。

      我已经用 #### 前缀的 cmets 标记了修改,并参考下面的解释对其进行了编号。

      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'(或 10),都代表连续 1
        • 如果不进行此更改,代码实际上需要六次后续匹配才能完成初始硬币翻转,总共连续七次(一个稍微不太直观的替代更改是将 if streak == 6: 替换为 if streak == 5:
      3. 从第二次翻转开始检查,使用range(1, len(CoinFlip))(注意列表是零索引的)
        • 当代码沿着列表回顾时,range() 以 0 开头的 for 循环会错误地将索引 0 与索引 -1 (the last element of the list) 进行比较
      4. (移动范围和)在每次检查之前重置streak 计数器
        • 如果不进行此更改,则实验中的初始条纹可能会添加到先前实验的部分条纹中(请参阅测试代码以获取建议的演示)
      5. 一旦我们发现一个条纹就退出检查

      本书中的这个问题有些不明确,最后一部分可以解释为“检查 [at least?] a [single?] [精确吗?] 六个 [或更多?] 的连续发现”。此解决方案将 check 解释为布尔评估(即我们只记录此列表包含或不包含条纹),并且非排他性地解释 a(即我们允许更长的条纹或多个条纹要计算;正如问题中提供的代码一样)。

      (可选 6.)测试代码

      注释掉的“示例/测试”允许您在每个实验中将通常随机生成的翻转切换为相同的已知值。在这种情况下,应计算为 100% 的固定列表。如果您不同意对任务规范的解释并禁用 (5.) 中描述的检查退出,您可能会期望程序报告 200%,因为在每个实验中都有两个不同的六个条纹。结合此输入禁用 break 会准确报告。

      您应该始终使用这种类型的技术(使用已知输入、验证输出)来说服自己,代码是否按其声称或您期望的那样工作。

      固定输入 CoinFlip = [ 'H', 'H', 'H', 'H', 'T', 'T', 'T' ] 可用于突出显示 (4.) 修复的问题。如果还原,代码将计算包含六个连续HT 的连续实验的百分比(全部使用此输入)为 50%。虽然 (5.) 修复了一个独立问题,但删除添加的 break 会进一步加剧错误并将计算的百分比提高到 99.99%。对于此输入,计算得到的包含六个连胜的百分比应为 0%。

      您会发现此处提供的完整代码产生了大约 80% 的估计值。这可能令人惊讶,但book 的作者暗示可能是这种情况:

      一个人几乎永远不会连续写下六个正面或六个反面,即使它很可能发生在真正随机的硬币翻转中。

      - 艾尔·斯威加特,Coin Flip Streaks

      您还可以考虑其他来源。 WolframAlpha 计算得出“在 100 次抛硬币中连续出现 6 次正面”的机会约为 1 比 2。在这里,我们正在估计连续 6 个(或更多)正面连续六个(或更多)反面的机会,这你可以期待更有可能。作为这种累积效应的一个更简单、独立的例子:考虑从一副普通扑克牌中挑选红心的几率是 52 分之 13,但挑选红心方块的几率是 52 分之 26 .


      计算注意事项

      这也有助于理解作者在计算百分比时也采取了捷径。这可能会使查看最终计算的初学者感到困惑。

      召回,计算百分比:

      我们知道要运行的实验总数将是 10000

      因此

      后记: 我冒昧地将最后一行中的100 更改为100.0。这允许代码在 Python 2 中正确计算百分比。这对于 Python 3 不是必需的,如问题和书中所述。

      【讨论】:

        【解决方案6】:

        我的业余尝试

        import random
        
        #reset strakes
        numberOfStreaks = 0
        #main loop
        for experimentNumber in range(10000):
        
            # Code that creates a list of 100 'heads' or 'tails' values.
            # assure the list is empty and all counters are 0
            coinFlip=[]
            H=0
            T=0
            for fata in range(100):
                # generate random numbers for head / tails
                fata = random.randint(0,1)
                #if head, append 1 head and reset counter for tail
                if fata == 0:
                    coinFlip.append('H')
                    H += 1
                    T = 0
                #else if tail append 1 tail and reset counter for head
                elif fata == 1:
                    coinFlip.append('T')
                    T += 1
                    H = 0
        
            # Code that checks if there is a streak of 6 heads or tails in a row.
            # when head and tail higher than 6 extract floored quotient and append it to numberOfStreaks,
            # this should take into consideration multiple streaks in a row.
        
            if H > 5 or T > 5:
                numberOfStreaks += (H // 6) or (T // 6) 
        
        print('Chance of streak: %s%%' % (numberOfStreaks / 100))
        

        输出:

        Chance of streak: 3.18%
        

        【讨论】:

        • 您能否添加一个解释,说明您的代码是做什么的?谢谢!
        【解决方案7】:

        此代码接缝给出了大约 54% 的正确概率,如上面之前的帖子中在 wolfram alpha 上所检查的那样

        import random
        numberOfStreaks = 0
        
        for experimentNumber in range(10000):
            # Code that creates a list of 100 'heads' or 'tails' values.
            hundredList = []
            streak = 0
            for i in range(100):
                hundredList.append(random.choice(['H','T']))
            # Code that checks if there is a streak of 6 heads or tails in a row.
            for i in range(len(hundredList)):
                if i == 0:
                    pass
                elif hundredList[i] == hundredList[(i-1)]:
                    streak += 1
                else:
                    streak = 0
        
                if streak == 6:
                    numberOfStreaks += 1
                    break
                
        print('Chance of streak: %s%%' % (numberOfStreaks / 100))
        

        【讨论】:

          【解决方案8】:

          我认为所有的答案都为问题增加了一些东西!!!杰出的!!! 但是,如果我们正在寻找 6 次连续的相同硬币翻转,它不应该是 'streak == 5'。 例如,THHHHHHT, streak == 6 在这里没有帮助。

          只需 100 次翻转的代码:

          coinFlipList = []
          
          for i in range(0,100):
              if random.randint(0,1)==0:
                  coinFlipList.append('H')
              else:
                  coinFlipList.append('T')
          print(coinFlipList)
          
          totalStreak = 0
          countStreak = 0
          for index,item in enumerate(coinFlipList):
              if index == 0:
                  pass
              elif coinFlipList[index] == coinFlipList[index-1]:
                  countStreak += 1
              else:
                  countStreak = 0
              if countStreak == 5:
                  totalStreak += 1
          print('Total streaks %s' %(totalStreak))
          

          如果我遗漏了什么,请告诉我。

          【讨论】:

            猜你喜欢
            • 2020-05-14
            • 2018-09-22
            • 2017-09-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-10-18
            • 1970-01-01
            相关资源
            最近更新 更多