我需要在Python中进行二项式测试,以便计算大约10000的'n'个数。
我已经使用scipy.misc.comb实现了一个快速的binomial_test函数,但是,它在n = 1000附近非常有限,我想因为它在计算阶乘或组合本身时达到了最大可表示的数字。这是我的功能:
from scipy.misc import comb
def binomial_test(n, k):
"""Calculate binomial probability
"""
p = comb(n, k) * 0.5**k * 0.5**(n-k)
return p
我如何使用本机python(或numpy,scipy ...)函数来计算二项式概率?如果可能的话,我需要scipy 0.7.2兼容代码。
非常感谢!
答案 0 :(得分:9)
编辑添加此评论:请注意,正如Daniel Stutzbach所提到的,“二项式测试”可能不是原始海报所要求的(虽然他确实使用了这个表达式)。他似乎要求二项分布的概率密度函数,这不是我在下面建议的。
你试过scipy.stats.binom_test吗?
rbp@apfelstrudel ~$ python
Python 2.6.2 (r262:71600, Apr 16 2009, 09:17:39)
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from scipy import stats
>>> print stats.binom_test.__doc__
Perform a test that the probability of success is p.
This is an exact, two-sided test of the null hypothesis
that the probability of success in a Bernoulli experiment
is `p`.
Parameters
----------
x : integer or array_like
the number of successes, or if x has length 2, it is the
number of successes and the number of failures.
n : integer
the number of trials. This is ignored if x gives both the
number of successes and failures
p : float, optional
The hypothesized probability of success. 0 <= p <= 1. The
default value is p = 0.5
Returns
-------
p-value : float
The p-value of the hypothesis test
References
----------
.. [1] http://en.wikipedia.org/wiki/Binomial_test
>>> stats.binom_test(500, 10000)
4.9406564584124654e-324
BTW:适用于scipy 0.7.2,以及当前的0.8 dev。
答案 1 :(得分:6)
任何看起来像comb(n, k) * 0.5**k * 0.5**(n-k)
的解决方案都不适用于大型n
。在大多数(所有?)平台上,Python float可以存储的最小值大约为2 ** - 1022。对于较大的n-k
或较大的k
,右侧将四舍五入为0.同样,comb(n,k)可能会变得如此之大,以至于它不适合浮动。
更强大的方法是将probability density function计算为cumulative distribution function中两个连续点之间的差异,这可以使用正则化的不完全beta函数计算(查看SciPy的“特殊函数”包)。在数学上:
pdf(p, n, k) = cdf(p, n, k) - cdf(p, n, k-1)
另一种选择是使用Normal approximation,这对于大n
非常准确。如果速度是一个问题,这可能是要走的路:
from math import *
def normal_pdf(x, m, v):
return 1.0/sqrt(2*pi*v) * exp(-(x-m)**2/(2*v))
def binomial_pdf(p, n, k):
if n < 100:
return comb(n, k) * p**k * p**(n-k) # Fall back to your current method
return normal_pdf(k, n*p, n*p*(1.0-p))
我还没有测试过代码,但这应该会给你一般的想法。
答案 2 :(得分:3)
GMPY还支持扩展精度浮点计算。例如:
>>> from gmpy import *
>>>
>>> def f(n,k,p,prec=256):
... return mpf(comb(n,k),prec) * mpf(p,prec)**k * mpf(1-p,prec)**(n-k)
...
>>> print(f(1000,500,0.5))
0.0252250181783608019068416887621024545529410193921696384762532089115753731615931
>>>
我指定了256位的浮点精度。顺便说一句,源伪造版本已经过时了。当前版本在code.google.com上维护,并支持Python 3.x. (免责声明:我是gmpy目前的维护者。)
casevh
答案 3 :(得分:1)
我会调查GNU Multi-Precision package(gmpy),它允许你执行任意精度计算:你可能会这样做:
comb(n, k, exact=1)/2**k/2**(n-k)
但是gmpy的长整数。
实际上,如果使用精确整数计算,则组合部分可轻松达到n = 10000 ;为此,您必须使用:
comb(n, k, exact=1)
而不是溢出的浮点近似值comb(n, k)
。
但是,正如原始海报所指出的那样,返回的(长整数)可能太长而不能乘以浮点数!
此外,很快就会遇到另一个问题:0.5**1000
= 9.3 ... e-302已经非常接近浮动下溢......
总结:如果您确实需要k
的所有n~10,000
的精确结果,则需要使用与原始帖子中的公式不同的方法,该方法受到双精度浮动的限制点算术。如上所述使用gmpy可能是一个解决方案(未经测试!)。
答案 4 :(得分:0)
不是特别是Python解决方案,但如果你可以处理小的小数错误,你可以尝试使用Stirling的近似n!:
comb(n,k)= n!/(k!*(n-k)!),其中n!对于大n来说,大约是sqrt(2 * Pi n)(n / e)^ n。
对于n> 1000,分数误差应该非常小。
对于大n的概率计算,使用对数表示中间结果:
log p = log(comb(n,k)) - n * log(2)
p = exp(log(p))
答案 5 :(得分:-1)
# This imports the array function form numpy
from numpy import array
# the following defines the factorial function to be used in the binomial commands/
# n+1 is used in the range to include the nth term
def factorial (n):
f=1
for x in range(1,n+1):
f=f*(x)
return f
# The follwong calculates the binomial coefficients for given values of n & k
def binomial (n,k):
b=1
b=(factorial(n)/(factorial(k)*factorial(n-k)))
return int(b)
# the following lines define the pascal triangle , and print it out for 20 rows./
# in order to include nth term, the n +1 term needs to be in the range. The commands/
# append the next binomial coeficiant to a raw first and then append rows to the triangle/
# and prints a 20 row size pascal triangle
def pascal(T):
triangle=[]
for n in range(T):
r=[]
for k in range(n+1):
r.append(binomial(n,k))
triangle.append(r)
return triangle
for r in pascal(20):
print((r))