python Numpy中的动态贴现累积和

slhcrj9b  于 2024-01-05  发布在  Python
关注(0)|答案(1)|浏览(117)

我有一个经常出现的问题,我有两个相同长度的数组:一个有值,一个有动态衰减因子;并且希望计算每个位置的衰减累积和的向量。使用Python循环来表达所需的递归,我们有以下内容:

c = np.empty_like(x)
c[0] = x[0]
for i in range(1, len(x)):
    c[i] = c[i-1] * d[i] + x[i]

字符串
Python代码非常清晰可读,但速度明显变慢。我可以通过使用Numba进行JIT编译,或者使用Cython进行预编译来解决这个问题。如果折扣因子是一个固定的数字(事实并非如此),我可以使用SciPy的信号库并执行lfilter(参见https://stackoverflow.com/a/47971187/1017986)。
有没有一种更“Numpythonic”的方式来表达这一点,而不牺牲清晰度或效率?

5jvtdoz2

5jvtdoz21#

从数学上讲,这是一个一阶变系数非齐次递推关系。
请注意,系数(在您的情况下,d[1:]中的值)必须不同于0。
下面是一种使用NumPy函数求解递归关系的方法。请注意,d[0]被设置为1,因为您的算法没有使用它,我需要它为1。在这个解决方案中,正如您所看到的,c中的值不依赖于c中以前的值。即,c[i]不依赖于c[i-1]

f = d.copy()
f[0] = 1
g = np.insert(x[1:], 0, 0)

pf = np.cumprod(f)
c = pf * (x[0] + np.cumsum(g / pf))

字符串
让我们举个例子。这里我定义了两个函数,一个用你的代码计算递归关系,另一个使用NumPy:

def rec(d, x):
    c = [x[0]]
    for i in range(1, len(x)):
        c.append(d[i] * c[-1] + x[i])
    return np.array(c)

def num(d, x):
    f = d.copy()
    f[0] = 1
    g = np.insert(x[1:], 0, 0)
    pf = np.cumprod(f)
    return pf * (x[0] + np.cumsum(g / pf))


以下是一些用法示例:

>>> rec(np.array([3, 4, 5.2, 6.1]), np.array([2, 3.2, 4, 5.7]))
array([  2.   ,  11.2  ,  62.24 , 385.364])
>>> num(np.array([3, 4, 5.2, 6.1]), np.array([2, 3.2, 4, 5.7]))
array([  2.   ,  11.2  ,  62.24 , 385.364])

>>> rec(np.array([3, 4.3, 5.2]), np.array([6.7, 7.1, 1.2]))
array([  6.7  ,  35.91 , 187.932])
>>> num(np.array([3, 4.3, 5.2]), np.array([6.7, 7.1, 1.2]))
array([  6.7  ,  35.91 , 187.932])


如果你对这个答案背后的数学细节感兴趣(这超出了这里的范围),请查看this维基百科页面。

编辑

这个解决方案虽然在数学上是正确的,但在计算过程中可能会引入数值问题(因为numpy.cumprod函数),特别是如果d包含可能接近0的值。

相关问题