如何计算一个数字数组的log阶乘



要计算的数量是log(k!),其中k可以是4000甚至更高,但当然日志会补偿。我试着计算sum(log(k)),这是相同的。

所以,我有一个大的整数数组,我想有效地计算sum(log(k))。这是我的尝试:

integers = np.asarray([435, 535, 242,])
score = np.sum(np.log(np.arange(1,integers+1)))

这可以工作,除了np.arange会为每个整数生成一个不同大小的数组,所以当我运行它时,它会给我一个错误(它应该)。

这个问题可以很容易地通过for循环解决,如下所示:

scores = []
for i in range(integers.shape[0]):
score = np.sum(np.log(np.arange(1,integer[i]+1)))
scores.append(score)

但是那太慢了。我实际的integers有数百万的值需要计算。

是否有一个有效的实现,基本上不需要一个for循环?我在想一个lambda函数或类似的东西,但我不确定如何应用它。任何帮助都是感激的!

math.lgamma怎么样?函数是阶乘,lgamma是log。

你不需要先计算阶乘再计算对数

也有gammaln在SciPy

代码,Python 3.9 x64 win10

import numpy as np
from scipy.special import gammaln
startf = 1 # start of factorial sequence
stopf  = 400 # end of of factorial sequence
q = gammaln(range(startf+1, stopf+1)) # n! = G(n+1)
print(q)

看起来很合理

你可以这样矢量化:

mi = integers.max()
ls = np.log(np.arange(2, mi + 1))

到目前为止的两个优化:您只需要范围到最大值,因为其他数字已经覆盖了,并且您不需要log(1)

现在取累加和:

cs = np.cumsum(ls)

所需的元素可以直接索引:

result = cs[integers - 2]

如果这是你需要做很多次的事情,并且你知道上界,这个解决方案将比使用math.lgmammascipy.special.gammaln要快得多,一旦你预先计算了cs的上界。

如果这是一次调用,下面是必须的一行代码:

np.cumsum(np.log(np.arange(2, np.max(integers))))[integers - 2]

如果内存是一个问题(我认为它也使他们更快),你可以做大多数的操作在原地:

mi = integers.max()
cs = np.arange(2, mi + 1)
np.cumsum(np.log(cs, out=cs), out=cs)