【问题标题】:Average number of streak of heads or tails in sequence of coin tossing抛硬币顺序中出现正面或反面的平均次数
【发布时间】:2022-01-26 17:48:45
【问题描述】:

下面的python代码代表一个小“游戏”:

  1. 我掷硬币 100 次,得到一系列正面和反面
  2. 我试图弄清楚在这个序列中,有多少次出现了 6 个正面或 6 个反面。
  3. 我想运行 10000 次,然后计算每个序列的平均条纹出现次数。

我知道解决方案是每个序列大约有 0.8 条条纹,但我得到了 1.6 条,但我无法弄清楚我做错了什么...... 我显然已经看到了其他解决方案,但我想弄清楚如何使这个特定的代码工作。

你能看看下面的代码,让我知道我做错了什么吗?

import random

numberOfStreaks = 0
possib = ['H', 'T']
folge = ''
x = 0

while x < 10000:
    for i in range (100):
        folge = folge + str(random.choice(possib))
    numberOfStreaks = folge.count('TTTTTT') + folge.count('HHHHHH')
    x = x + 1
print(numberOfStreaks)

【问题讨论】:

  • 您不会在每个 while 循环开始时重置 folge
  • 我看到的第一件事是你一遍又一遍地计算相同的条纹
  • 是 7 个“头”连续出现 1 或 2 次?
  • 是连续出现 12 个“头”、1、2、7 还是其他次数?在不知不觉中,没有人能真正提供准确的答案。
  • 即您如何“知道解决方案是每个序列大约有 0.8 条条纹”?

标签: python random sequence


【解决方案1】:

既然你“知道”你寻求的答案是 ~= 0.8:

我相信你误解了这个问题。我怀疑你真正想回答的问题是 Al Sweigart 的“Automate the Boring Stuff with Python”中的一个(不知名的)问题(强调我的):

如果你掷硬币 100 次......

... 编写一个程序来找出连续六个头或一个头的频率 六尾的条纹出现在随机生成的正面列表中,并且 尾巴。您的程序将实验分为两部分:第一部分 部分生成随机选择的“正面”和“反面”值列表, 第二部分检查其中是否有条纹。把这一切 循环中的代码,重复实验 10,000 次,所以我们可以找到 抛硬币的百分比(实验)包含 连续六个正面或反面

第 1 部分生成随机选择的“正面”和“反面”值列表):

observations = "".join(random.choice("HT") for _ in range(100))

第 2 部分检查其中是否有条纹。):

has_streak = observations.find("H"*6) != -1 or observations.find("T"*6) != -1

Part Do Loop将代码放入循环中,重复实验 10,000 次):

experimental_results = []
for _ in range(10_000):
    observations = "".join(random.choice("HT") for _ in range(100))
    has_streak = observations.find("H"*6) != -1 or observations.find("T"*6) != -1 
    experimental_results.append(has_streak)

部分获取结果找出包含条纹的实验百分比):

print(sum(experimental_results)/len(experimental_results))

这应该给你一些接近:

0.8

完整代码:

import random
experimental_results = []
for _ in range(10_000):
    observations = "".join(random.choice("HT") for _ in range(100))
    has_streak = observations.find("H"*6) != -1 or observations.find("T"*6) != -1 
    experimental_results.append(has_streak)
print(sum(experimental_results)/len(experimental_results))

如果您想要回答的问题是:

平均而言,至少 6 次连续出现的次数 抛硬币 100 次是正面还是反面?

然后我们可以对它们进行计数并平均:

import random

def count_streaks(observations):
    streaks = 0
    streak_length = 1
    prior = observations[0]
    for current in observations[1:]:
        if prior == current:
            streak_length += 1
            if streak_length == 6:
                streaks += 1
        else:
            streak_length = 1

        prior = current
    return streaks

experimental_results = []
for _ in range(10_000):
    observations = [random.choice("HT") for _ in range(100)]
    observed_streaks = count_streaks(observations)
    experimental_results.append(observed_streaks)
print(sum(experimental_results)/len(experimental_results))

这会给你一个大约的结果:

1.50

注意:

您的代码使用folge.count('TTTTTT')。我相信这段代码和任何使用类似策略的答案都可能(在 10k 次实验过程中)高估了答案,因为 ("H"*12).count("H"*6)2 而不是 1

例如:

@samwise (Probability of streak of heads or tails in sequence of coin tossing) 的这个出色的回答始终在以下范围内产生结果:

1.52

【讨论】:

  • 你说得对,我正在尝试在“使无聊的东西自动化”中找到“硬币翻转条纹”问题的答案。我确实误解了那个练习。感谢您的帮助,这很好地回答了我的问题!
【解决方案2】:

您每次都通过x 循环附加到folge,因此 10000 次不同的运行并不是相互独立的——您没有 10000 次不同的一组 100 次投掷,您只有一个一组 1000000 次投掷(其中会有更多的条纹,因为在 100 次投掷后你不会“打破”它)。

您要做的是计算每组 100 次投掷的连胜数,然后取所有这些数的平均值:

from random import choice
from statistics import mean

def count_streaks(folge: str) -> int:
    return folge.count("TTTTTT") + folge.count("HHHHHH")

print(mean(
    count_streaks(''.join(
        choice("HT") for _ in range(100)
    ))
    for _ in range(10000)
))

【讨论】:

  • "".join(random.choices("HT", k=100)) 也可能更好
  • 虽然不太可能,"xxxxxxxxxxxxxx".count("xxxxxxx") == 2。这就引出了一个问题,如果 6 个“T”是命中,那么 7 个“T”是两个命中还是一个命中?如果是一次命中,那么为什么要运行 12 次,每个代码两次命中。如果预计 12 次运行是 2 次安打,为什么不是 7 次安打。总而言之,这个答案不能保证有效。
  • 我可以看到这个论点,无论是 12 次运行被解释为一个连胜或两个连续的连胜; OP没有澄清。如果这只能算作一次连胜,那么我会使用itertools.groupby 而不是str.count 来实现count_streaks
  • 我要求 OP 澄清如何计算命中,因为我同意这可能是一个有效的解决方案 IIF 两次不重叠的连续运行 6 计为 2 次命中。
  • 我在 Al Sweigart 的“用 python 自动化无聊的东西”中寻找 Coin Flip Streak 练习的答案,但 John SG 在他上面的回答中解释了我是如何误解了这个问题的。但是,您的回答使我想要工作的代码工作(即使我误解了书中的任务)。非常感谢!
猜你喜欢
  • 2023-03-06
  • 1970-01-01
  • 2017-07-02
  • 1970-01-01
  • 2019-01-07
  • 1970-01-01
  • 1970-01-01
  • 2022-10-30
  • 1970-01-01
相关资源
最近更新 更多