numpy 中的整数 optimization/maximization

Integer optimization/maximization in numpy

我需要 estimate 人口规模,方法是找到使 scipy.misc.comb(n, a)/n**b 最大化的 n 值,其中 ab 是常量。 nab 都是整数。

显然,我可以在 range(SOME_HUGE_NUMBER) 中创建一个循环,计算每个 n 的值,并在曲线出现拐点时跳出循环。但是我想知道是否有一种优雅的方式使用(比如)numpy/scipy 来做到这一点,或者是否有其他一些优雅的方式来做到这一点只是在纯 Python 中(例如像牛顿方法的整数等效? )

只要您的数字 n 相当小(小于大约 1500),我猜最快的方法是实际尝试所有可能的值。您可以使用 numpy:

快速完成此操作
import numpy as np
import scipy.misc as misc

nMax = 1000
a = 77
b = 100
n = np.arange(1, nMax+1, dtype=np.float64)
val = misc.comb(n, a)/n**b
print("Maximized for n={:d}".format(int(n[val.argmax()]+0.5)))
# Maximized for n=181

这不是特别优雅,但对于 n 的范围来说相当快。问题是对于 n>1484,分子可能已经变得太大而无法存储在 float 中。然后此方法将失败,因为您将 运行 溢出。但这不仅仅是 numpy.ndarray 不能使用 python 整数的问题。即使有了它们,您也无法计算:

misc.comb(10000, 1000, exact=True)/10000**1001

因为您想在两个数字的除法中得到一个浮点数,结果大于 python 中的 float 可以容纳的最大值(max_10_exp = 1024 在我的系统上。参见 sys.float_info().)。在那种情况下,您也不能使用 range。如果你真的想做那样的事情,你将不得不在数字上更加小心。

你基本上有一个你想要最大化的 n 的平滑函数。 n 必须是整数,但我们可以将该函数视为实数函数。在这种情况下,n 的最大积分值必须接近(接近)最大实数值。

我们可以使用伽玛函数将 comb 转换为实函数,并使用数值优化技术找到最大值。另一种方法是用斯特林近似代替阶乘。这给出了一个适度复杂但易于处理的代数表达式。这个表达式不难区分,置零求极值。

我这样做并获得了

n * (b + (n-a) * log((n-a)/n) ) = a * b - a/2

这在代数上并不简单,但在数值上很容易解决(例如,如您所建议的,使用牛顿法)。

我可能在代数上犯了一个错误,但我在 Wolfram Alpha 中输入了 a = 77,b = 100 的例子并得到了 180.58,所以这个方法似乎有效。