Python 计算大数的二项式概率

Python 计算大数的二项式概率,python,algorithm,numpy,probability,binomial-coefficients,Python,Algorithm,Numpy,Probability,Binomial Coefficients,我想在python上计算二项式概率。我试着运用这个公式: probability = scipy.misc.comb(n,k)*(p**k)*((1-p)**(n-k)) 我得到的一些概率是无限的。我检查了一些p=inf的值,其中一个是n=450000,k=17。该值必须大于1e302,1e302是浮点处理的最大值 然后我尝试使用sum(np.random.binomial(n,p,numberOfTrials)==valueOfInterest)/numberOfTrials 这将绘制num

我想在python上计算二项式概率。我试着运用这个公式:

probability = scipy.misc.comb(n,k)*(p**k)*((1-p)**(n-k))
我得到的一些概率是无限的。我检查了一些p=inf的值,其中一个是n=450000,k=17。该值必须大于1e302,1e302是浮点处理的最大值

然后我尝试使用
sum(np.random.binomial(n,p,numberOfTrials)==valueOfInterest)/numberOfTrials

这将绘制numberOfTrials样本,并计算绘制兴趣值的平均次数


这不会产生任何无限值。然而,这是一种有效的方法吗?为什么这种方法不会增加任何无穷大的值,而计算概率会增加无穷大的值呢?

在对数域中计算组合函数和指数函数,然后将它们增加到指数

大概是这样的:

combination_num = range(k+1, n+1)
combination_den = range(1, n-k+1)
combination_log = np.log(combination_num).sum() - np.log(combination_den).sum()
p_k_log = k * np.log(p)
neg_p_K_log = (n - k) * np.log(1 - p)
p_log = combination_log + p_k_log + neg_p_K_log
probability = np.exp(p_log)

消除因数字过大而导致的数值下溢/溢出。在您使用
n=450000
p=0.5,k=17
的示例中,它返回
p_log=-311728.4
,i。e、 ,最终概率的对数非常小,因此在采用
np.exp
时会发生下溢。但是,您仍然可以使用对数概率。

我认为您应该使用对数进行所有计算:

from scipy import special, exp, log
lgam = special.gammaln

def binomial(n, k, p):
    return exp(lgam(n+1) - lgam(n-k+1) - lgam(k+1) + k*log(p) + (n-k)*log(1.-p))

因为您使用的是scipy,所以我想我应该提到scipy已经实现了统计分布。还要注意,当n这么大时,二项分布很好地近似于正态分布(如果p非常小,则为泊松分布)


要避免类似于零的多重性,请使用这样的逐步乘法

def Pbinom(N,p,k):
    q=1-p
    lt1=[q]*(N-k)
    gt1=list(map(lambda x: p*(N-k+x)/x, range(1,k+1)))
    Pb=1.0
    while (len(lt1) + len(gt1)) > 0:
        if Pb>1:
            if len(lt1)>0:
                Pb*=lt1.pop()
            else:
                if len(gt1)>0:
                    Pb*=gt1.pop()
        else:
            if len(gt1)>0:
                Pb*=gt1.pop()
            else:
                if len(lt1)>0:
                    Pb*=lt1.pop()
    return Pb

还要注意
scipy.special
函数
xlogy
,它比
k*log(p)
更稳定。
def Pbinom(N,p,k):
    q=1-p
    lt1=[q]*(N-k)
    gt1=list(map(lambda x: p*(N-k+x)/x, range(1,k+1)))
    Pb=1.0
    while (len(lt1) + len(gt1)) > 0:
        if Pb>1:
            if len(lt1)>0:
                Pb*=lt1.pop()
            else:
                if len(gt1)>0:
                    Pb*=gt1.pop()
        else:
            if len(gt1)>0:
                Pb*=gt1.pop()
            else:
                if len(lt1)>0:
                    Pb*=lt1.pop()
    return Pb