假设我知道“成功”的概率为P。我运行了N次测试,并且看到S成功。该测试类似于抛掷重量不均的硬币(也许正面成功,反面失败)。
我想知道看到S个成功或比S个成功可能性小的几率的大概概率。
例如,如果P为0.3,N为100,而我获得20次成功,那么我正在寻找获得20次 或更少 成功的可能性。
如果在另一个避风港上,P为0.3,N为100,而我获得40次成功,那么我正在寻找获得40次成功的可能性。
我知道这个问题与查找二项式曲线下的面积有关,但是:
我应该强调,此计算必须快速,并且理想情况下应该可以使用标准的64位或128位浮点计算来确定。
我正在寻找一个接受P,S和N并返回概率的函数。因为我比数学符号更熟悉代码,所以我希望任何答案都使用伪代码或代码。
精确的二项分布
def factorial(n): if n < 2: return 1 return reduce(lambda x, y: x*y, xrange(2, int(n)+1)) def prob(s, p, n): x = 1.0 - p a = n - s b = s + 1 c = a + b - 1 prob = 0.0 for j in xrange(a, c + 1): prob += factorial(c) / (factorial(j)*factorial(c-j)) \ * x**j * (1 - x)**(c-j) return prob >>> prob(20, 0.3, 100) 0.016462853241869437 >>> 1-prob(40-1, 0.3, 100) 0.020988576003924564
正常估计,适合大n
import math def erf(z): t = 1.0 / (1.0 + 0.5 * abs(z)) # use Horner's method ans = 1 - t * math.exp( -z*z - 1.26551223 + t * ( 1.00002368 + t * ( 0.37409196 + t * ( 0.09678418 + t * (-0.18628806 + t * ( 0.27886807 + t * (-1.13520398 + t * ( 1.48851587 + t * (-0.82215223 + t * ( 0.17087277)))))))))) if z >= 0.0: return ans else: return -ans def normal_estimate(s, p, n): u = n * p o = (u * (1-p)) ** 0.5 return 0.5 * (1 + erf((s-u)/(o*2**0.5))) >>> normal_estimate(20, 0.3, 100) 0.014548164531920815 >>> 1-normal_estimate(40-1, 0.3, 100) 0.024767304545069813
泊松估计:适用于大n和小p
import math def poisson(s,p,n): L = n*p sum = 0 for i in xrange(0, s+1): sum += L**i/factorial(i) return sum*math.e**(-L) >>> poisson(20, 0.3, 100) 0.013411150012837811 >>> 1-poisson(40-1, 0.3, 100) 0.046253037645840323