如何使用计算方法(例如使用Python)找到以下期望的概率?

如何使用计算方法(例如使用Python)找到以下期望的概率?,python,statistics,probability,computation,Python,Statistics,Probability,Computation,我们班有64名学生。我们进行了一轮随机团队分配,不久将进行第二轮。在每一轮中,我们将学生随机分成16组,每组4人 第一轮中没有一对队友在第二轮中再次成为队友的概率是多少?如果“计算”是指“模拟”: 当然,10000个例子的样本很小,但它应该开始给你一个想法。你可以运行几次,看看频率(作为概率的估计值)是如何变化的,并计算置信区间等等。让我们根据学生的第一轮团队给他们贴上标签: 0000 1111 2222 3333 4444 5555 6666 7777 8888 9999 AAAA BBBB

我们班有64名学生。我们进行了一轮随机团队分配,不久将进行第二轮。在每一轮中,我们将学生随机分成16组,每组4人

第一轮中没有一对队友在第二轮中再次成为队友的概率是多少?

如果“计算”是指“模拟”:


当然,10000个例子的样本很小,但它应该开始给你一个想法。你可以运行几次,看看频率(作为概率的估计值)是如何变化的,并计算置信区间等等。

让我们根据学生的第一轮团队给他们贴上标签:

0000 1111 2222 3333 4444 5555 6666 7777 8888 9999 AAAA BBBB CCCC DDDD EEEE FFFF
不受限制地分配第二轮团队的方法数量如下:

64! / ((4! ** 16) * (4! ** 16)) == 864285371844932000669608560277139342915848604
 ^        ^            ^
 |        |        ways of rearranging each round-2 team
 |     indistinguishable arrangements for round-1 team members
raw number of permutations
分配第二轮团队而不分配每个团队重复的方法非常复杂,因为我们分配第一个团队的方式会改变第二个团队可用的组合(依此类推)。但它仍然应该是易于处理的聪明的数学和仔细的记忆

from functools import lru_cache

# lookup table for `choose(n, k)` for n up to 16 and k up to 4
ncr = {}
for n in range(17):
    nn   = n
    ntok = 1
    ktok = 1
    ncr[n, 0] = 1
    for k in range(1, min(n, 4) + 1):
        ntok *= nn
        nn -= 1
        ktok *= k
        ncr[n, k] = ntok // ktok

@lru_cache(maxsize=None)
def team_combos(zeros, ones, twos, threes, fours):
    """
    Calculate the number of unique second-round 4-person
      team combinations such that no team has members from
      the same first-round team.
    """
    if ones or twos or threes or fours:
        total_ways = 0
        # number of members to take from teams having one person remaining
        for b in range(min(ones, 4) + 1):
            zeros_ = zeros + b
            b_ways = ncr[ones, b]
            b_rem = 4 - b   # number of members yet to be chosen
            # number of members to take from teams having two persons remaining
            for c in range(min(twos, b_rem) + 1):
                ones_ = ones - b + c
                bc_ways = b_ways * ncr[twos, c]
                bc_rem = b_rem - c  # number of members yet to be chosen
                # number of members to take from teams having three persons remaining
                for d in range(min(threes, bc_rem) + 1):
                    e = bc_rem - d  # number of members yet to be chosen
                    # ... all of which _must_ now come from
                    #   teams having four persons remaining
                    if e <= fours:
                        bcde_ways = bc_ways * ncr[threes, d] * ncr[fours, e]
                        total_ways += bcde_ways * team_combos(zeros_, ones_, twos - c + d, threes - d + e, fours - e)
        return total_ways
    else:
        return 1
那么最后的概率就是


非常感谢。这是非常有用的。顺便说一句,“一些普通的队友”是最有可能的,正如一点统计直觉应该显示的那样,“根本没有普通队友”的概率非常低,因此需要先进的统计技术来进行稳健的评估(超越我那个时代的统计101)。我相信你们的教授意识到了这一点,并将其作为更高、更难的任务的垫脚石。我早期发表的一篇文章正是关于一种更好的启发式方法来估计非常罕见事件的概率——尽管全世界都忽略了我,并且一直在愉快地使用良好的图灵估计,至少我知道得更清楚:-)。对不起,我刚才错写了一些东西……所以我刚刚删除了它!对不起!你的回答很有帮助。我真的很感谢你的帮助@user118464,NP,看到了你的编辑并修改了我自己的评论——现在当你删除你的最新评论时,我将删除这一条(而不是之前关于Martelli启发式在Turing Good上的改进,30年后我仍然对此感到自豪,这为我的“形状如何影响力量”开辟了道路)2000年1月和2月《桥梁世界》杂志上的文章,我认为这是我最大的成就!-)关键的直觉,好的和图灵都是第一位!,就是说,如果某个组合非常罕见,那么标准的stats 101方法可以估计出它的错误行为概率,所以你需要更多。。。!谢谢你的帮助!
from functools import lru_cache

# lookup table for `choose(n, k)` for n up to 16 and k up to 4
ncr = {}
for n in range(17):
    nn   = n
    ntok = 1
    ktok = 1
    ncr[n, 0] = 1
    for k in range(1, min(n, 4) + 1):
        ntok *= nn
        nn -= 1
        ktok *= k
        ncr[n, k] = ntok // ktok

@lru_cache(maxsize=None)
def team_combos(zeros, ones, twos, threes, fours):
    """
    Calculate the number of unique second-round 4-person
      team combinations such that no team has members from
      the same first-round team.
    """
    if ones or twos or threes or fours:
        total_ways = 0
        # number of members to take from teams having one person remaining
        for b in range(min(ones, 4) + 1):
            zeros_ = zeros + b
            b_ways = ncr[ones, b]
            b_rem = 4 - b   # number of members yet to be chosen
            # number of members to take from teams having two persons remaining
            for c in range(min(twos, b_rem) + 1):
                ones_ = ones - b + c
                bc_ways = b_ways * ncr[twos, c]
                bc_rem = b_rem - c  # number of members yet to be chosen
                # number of members to take from teams having three persons remaining
                for d in range(min(threes, bc_rem) + 1):
                    e = bc_rem - d  # number of members yet to be chosen
                    # ... all of which _must_ now come from
                    #   teams having four persons remaining
                    if e <= fours:
                        bcde_ways = bc_ways * ncr[threes, d] * ncr[fours, e]
                        total_ways += bcde_ways * team_combos(zeros_, ones_, twos - c + d, threes - d + e, fours - e)
        return total_ways
    else:
        return 1
>>> team_combos(0, 0, 0, 0, 16)   # start with 16 four-person teams
6892692735539278753058456514221737762215000
>>> 6892692735539278753058456514221737762215000 / 864285371844932000669608560277139342915848604
0.0079750195480295