5

我无法理解SciPy函数的文档。scipy.stats.hypergeom在我的程序中,我考虑了各种牌组,并尝试找出各种平局的概率。该hypergeom课程似乎正好有这个,但它的文档假设了一堆我没有的术语知识。谷歌搜索将我带到 Wikipedia 和 Wolfram MathWorld,两者都假设如果你问这种事情,你已经阅读了从 dang Principia Mathematica向前的所有内容,只需要一点复习 - 所以它们实际上并没有帮助. 因为这个问题是“我如何将这个特定的代码块应用到我的问题上?” 我在问堆栈溢出。

我有一个形式的问题“如果你有一副N牌,其中M是感兴趣的牌,那么在前Q牌中至少有 1 张感兴趣的牌的几率是多少?” 我也有一个形式的问题“如果你有一副N牌,其中M是感兴趣的牌,你必须从牌组中抽多少张牌才能有 90% 的机会其中一张是感兴趣的卡片?” 前一个问题与 SciPy 文档中给出的示例问题非常接近,但它不是一回事,而且方法列表对我来说都是行话——我实际上无法说出其中哪一个是我需要的。我也无法确定使用哪种方法来解决后一种问题。

的方法scipy.stats.hypergeom实际上做了什么,它们的论点是什么,我如何将它们应用于我的问题?假设我是一个中等聪明的高中生,而不是数学博士生。

4

2 回答 2

4
scipy.stats.hypergeom.pmf(k, M, n, N)

返回概率:从M张牌中,有n张被标记,如果你随机选择N张没有放回的牌,正好有k张牌被标记。

所以你可以得到你想要的答案(使用你的变量名)

def pick_Q(N, M, Q):
    """
    Given a deck of N cards, where M are marked,
    and Q cards are taken randomly without replacement,
    return the probability that at least one marked card is taken.
    """
    return sum(scipy.stats.hypergeom.pmf(k, N, M, Q) for k in xrange(1,Q+1))

(标记1张牌,标记2张牌,标记3张牌......标记N张牌的几率总和)。

幸运的是,有一种更快的方法 - 至少一张标记的牌被拿走的概率是没有标记的牌被挑选的概率的另一面。所以你可以做

def pick_Q(N, M, Q):
    """
    Given a deck of N cards, where M are marked,
    and Q cards are taken randomly without replacement,
    return the probability that at least one marked card is taken.
    """
    return 1. - scipy.stats.hypergeom.pmf(0, N, M, Q)

对于您的第二个问题,似乎没有任何功能可以满足您的需求;但是,您可以从

def how_many_to_pick(N, M, prob):
    """
    Given a deck of N cards, M of which are marked,
    how many do you have to pick randomly without replacement
    to have at least prob probability of picking at least one marked card?
    """
    for q in xrange(1, M+1):
        if pick_Q(N, M, q) >= prob:
            return q
    raise ValueError("Could not find a value for q")

编辑:

scipy.stats.hypergeom.cdf(k, M, n, N)

给定一副 M 牌,其中 n 被标记,随机挑选 N 张,不放回,找出选出k 或更少标记的牌的几率。(您可以将其视为 .pmf 的积分)

那么 .sf(k, M, n, N) 是 .cdf 的反面——超过 k 个标记的牌被选中的几率。

例如,

 k      pmf(k,52,13,4)   cdf(k,52,13,4)   sf(k,52,13,4)
     (exactly k picked)  ( <= k picked)   ( > k picked)
---  -----------------  ---------------  --------------
 0       0.303817527      0.303817527      0.696182473
 1       0.438847539      0.742665066      0.257334934
 2       0.213493397      0.956158463      0.043841537
 3       0.041200480      0.997358944      0.002641056
 4       0.002641056      1.000000000      0.000000000

编辑2:

实际上,这提供了另一种编写 pick_Q 函数的方法——“挑选 1 张或更多标记的卡片”可以改写为“挑选超过 0 张标记的卡片”,所以

def pick_Q(N, M, Q):
    """
    Given a deck of N cards, where M are marked,
    and Q cards are taken randomly without replacement,
    return the probability that at least one marked card is taken.
    """
    return scipy.stats.hypergeom.sf(0, N, M, Q)
于 2012-07-02T01:57:44.507 回答
2

值得注意的是,这不是一个不使用就很难解决的问题scipy。假设我们有 10 个项目的随机排列:

4, 7, 2, 3, 0, 9, 1, 5, 6, 8

还有一组“赢家” 2, 4, 6。由于我们只关心赢家和输家,我们可以稍微简化一下表示:

1, 0, 1, 0, 0, 0, 0, 0, 1, 0

我们可以对任何一组 10 个可能的项目和 3 个获胜者做同样的事情;并且给定这 10 个项目的任何可能排列,我们可以执行相同的简化。所以真正发生的是每个排列“选择” 3 个获胜指数,而牌组中获胜者的可能排列数量是10 选择 3,或者10! / (3! * 7!)

现在我们需要知道的是,有多少可能的获胜者安排在第一Q张牌中至少给了我们一个获胜者。由于更容易计算有多少安排在第一张牌中给了我们Q赢家,所以我们将计算它。所以我们想要的,用最具体的术语来说,是看起来像这样的序列的数量(对于 Q = 4):

0, 0, 0, 0 | 0, 1, 0, 1, 1, 0

在这里,我们已经对序列进行了分区,分区之前的值应该始终为零。有多少这样的序列?嗯,这样的序列与包含 6 张牌中 3 位获胜者的序列一样多。所以这是 6 选择 3,即6! / (3! * 3!)

因此,要获得在 10 个值的随机排列中,前三个不包含获胜者的几率,我们只需计算以下内容:

(6 choose 3) / (10 choose 3)

为了获得相反的赔率(即前三个中至少一个包含获胜者的赔率),我们这样做:

1 - (6 choose 3) / (10 choose 3)

total用= Nwinners=Mtries=概括Q

1 - ((N - Q) chose M) / (N chose M)

在 python 中,它看起来像这样:

>>> def choose(n, x):
...     return reduce(mul, range(n, n - x, -1)) / math.factorial(x)
...
>>> def ntries_win_odds(total, winners, tries):
...     inv = (choose(total - tries, winners) / float(choose(total, winners)))
...     return 1 - inv

反方向求解并不难——我们只需要一个“逆向选择”函数来求解c = n choose xn定的cx。我觉得这里有算法改进的空间,但这有效:

>>> def choose_x_pseudoinverse(target, x):
...     for n in itertools.count(start=x):
...         if choose(n, x) >= target:
...             return n

现在,解决尝试:

odds = 1 - ((total - tries) chose winners) / (total chose winners)
(1 - odds) * (total choose winners) = ((total - tries) chose winners)
choose_x_inv((1 - odds) * (total choose winners), winners) = total - tries
tries = total - choose_x_inv((1 - odds) & (total choose winners), winners)

在 Python 中,这是

def ntries_from_odds(odds, total, winners):
    inv_odds = 1 - odds
    tCw = choose(total, winners)
    return total - choose_x_pseudoinverse(inv_odds * tCw, winners)  
于 2012-07-02T02:55:34.310 回答