简介
我正在尝试使用IPython绘制超几何分布。分布的概率函数包含三个二项式系数。
因为我将在系数中放入的值非常大,例如。 1e28,我决定使用自己的函数计算二项式系数,其中我使用斯特林近似的二阶。
由于二项式系数太大而无法直接放入变量并且直接相乘,我决定计算它们的对数并将它们相互添加。为了获得最终概率,我只需将结果放在exp
函数中。由于概率相对“正常”(最大值为2.7e24),因此应该没有更多问题......除非有。
问题。
我所提到的'结果',这是概率最终结束的记录,其值应该在-6.2e24到1.3e14之间。相比之下,数学最大值的对数大约为56。
另一个问题是当放大时,绘图上的曲线非常锯齿状。缩小时一切看起来都很好。曲线是平滑的,其最大值是分布的平均值:
但是当我放大概率函数的大部分峰值时的平均值,因为标准偏差非常小,我得到了这个:
红线表示平均值,黑线表示平均值+/-标准偏差。 虽然它看起来很漂亮,但它不是我需要的,这是一条平滑的曲线。
问题。
有人可以解释为什么(1)值太大而且(2)为什么曲线是锯齿状的以及我如何修复它们?
代码。
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
#Returns the log of "n choose k" calculated with 2nd order Stirling's approximation
def l_cb(n, k):
if (k > n) or (n < 0) or (n < 0):
print "Invalid values for the binomial coefficient:", "n =", n, ", k =", k, "."
return 0.0
if (k == n) or (k == 0) or (n == 0):
return 0.0
A = (n + 0.5) * np.log(n) - (k + 0.5) * np.log(k) - (n - k + 0.5) * np.log(n - k)
B = np.log(1 + 1 / (12.0 * n)) - np.log(1 + 1 / (12.0 * k)) - np.log(1 + 1 / (12.0 * (n - k)))
return - 1/2 * np.log(2 * np.pi) + A + B
K = 2.24e28
k = 2.24e27
N = 2.7e25
#Mathematical maximum of P. np.log(MAX) is about 56. l_P is way too big.
MAX = (k + 1) * (N + 1) / (K + 2)
#Mathematical average of n
AVG = N * k / K
#Mathematical standard deviation of P.
SD = np.sqrt(N * k * (K - N) * (K - k) / K ** 2 / (K - 1))
n = np.linspace(AVG - 50e12, AVG + 50e12, 1001)
l_P = np.zeros(len(n))
#Calculating log(P).
for i in xrange(len(l_P)):
l_P[i] = l_cb(N, n[i]) + l_cb(K - N, k - n[i]) - l_cb(K, k)
#Marking AVG, AVG - SD, AVG + SD
y = np.linspace(-4e14, 5e14, len(n))
x_AVG = np.ones(len(n))
x_SD_L = np.ones(len(n)) - SD / AVG
x_SD_R = np.ones(len(n)) + SD / AVG
plt.plot(n / AVG, l_P, x_AVG, y, 'r', x_SD_L, y, 'k', x_SD_R, y, 'k')
plt.xlabel('n / AVG')
plt.ylabel('log(P)')