我想在python上计算二项式概率。我试图应用公式:
probability = scipy.misc.comb(n,k)*(p**k)*((1-p)**(n-k))
我得到的一些概率是无限的。我检查了一些p = inf的值。对于其中一个,n = 450,000,k = 17。该值必须大于1e302,这是浮点数处理的最大值。
然后我尝试使用sum(np.random.binomial(n,p,numberOfTrials)==valueOfInterest)/numberOfTrials
这会绘制numberOfTrials样本,并计算绘制valueOfInterest值的平均次数。
这不会带来任何无限的价值。但是,这是一种有效的方法吗?为什么这种方式不会提高任何无限值而计算概率呢?
答案 0 :(得分:8)
因为你正在使用scipy,我想我会提到scipy已经实现了统计分布。还要注意,当n很大时,二项分布很好地用正态分布近似(或者如果p非常小则为泊松)。
n = 450000
p = .5
k = np.array([17., 225000, 226000])
b = scipy.stats.binom(n, p)
print b.pmf(k)
# array([ 0.00000000e+00, 1.18941527e-03, 1.39679862e-05])
n = scipy.stats.norm(n*p, np.sqrt(n*p*(1-p)))
print n.pdf(k)
# array([ 0.00000000e+00, 1.18941608e-03, 1.39680605e-05])
print b.pmf(k) - n.pdf(k)
# array([ 0.00000000e+00, -8.10313274e-10, -7.43085142e-11])
答案 1 :(得分:7)
在日志域中工作以计算组合和取幂函数,然后将它们提升为指数。
这样的事情:
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。例如,最终概率的对数非常小,因此在取np.exp
时发生下溢。但是,您仍然可以使用对数概率。
答案 2 :(得分:5)
我认为你应该使用对数进行所有计算:
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))
答案 3 :(得分:0)
为了避免像无穷大那样的多重性,请使用逐步乘法。
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