使用numpy计算滚动加权和

qnyhuwrf  于 2022-12-23  发布在  其他
关注(0)|答案(1)|浏览(150)

我很想知道是否有更好的方法来计算这个"滚动加权和"(不确定实际的术语是什么,但我会提供一个例子来进一步澄清),我问这个问题是因为我确信我当前的代码片段在内存使用方面没有用最好的方法编写,而且有机会通过使用numpy更高级的函数来提高它的性能。
示例:

import numpy as np

A = np.append(np.linspace(0, 1, 10), np.linspace(1.1, 2, 30))
np.random.seed(0)

B = np.random.randint(3, size=40) + 1

# list of [(weight, (lower, upper))]
d = [(1, (-0.25, -0.20)), (0.5, (-0.20, -0.10)), (2, (-0.10, 0.15))]

在Python 3.7中:

## A
array([0.        , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
       0.55555556, 0.66666667, 0.77777778, 0.88888889, 1.        ,
       1.1       , 1.13103448, 1.16206897, 1.19310345, 1.22413793,
       1.25517241, 1.2862069 , 1.31724138, 1.34827586, 1.37931034,
       1.41034483, 1.44137931, 1.47241379, 1.50344828, 1.53448276,
       1.56551724, 1.59655172, 1.62758621, 1.65862069, 1.68965517,
       1.72068966, 1.75172414, 1.78275862, 1.8137931 , 1.84482759,
       1.87586207, 1.90689655, 1.93793103, 1.96896552, 2.        ])

## B
array([1, 2, 1, 2, 2, 3, 1, 3, 1, 1, 1, 3, 2, 3, 3, 1, 2, 2, 2, 2, 1, 2,
       1, 1, 2, 3, 1, 3, 1, 2, 2, 3, 1, 2, 2, 2, 1, 3, 1, 3])

预期溶液:

array([ 6. ,  6.5,  8. , 10.5, 12. , 11. , 11.5, 11.5,  6.5, 13.5, 25. ,
       27.5, 30.5, 34.5, 37.5, 36. , 35. , 35. , 34. , 34.5, 34. , 36.5,
       33. , 34. , 34.5, 34.5, 36. , 39. , 37. , 36. , 37. , 36.5, 37.5,
       39. , 36.5, 37.5, 34. , 31. , 27.5, 23. ])

我想翻译成代码的逻辑是:
让我们看看10.5(期望解中的第四个元素)是如何计算的。d表示嵌套元组的集合,其中第一个浮点数元素为weight,第二个元组元素为bounds(形式为(lower, upper))。
我们查看A的第四个元素(0.33333333),并对d中的每个元组应用bounds,对于d中的第一个元组:

0.33333333 + (-0.25) = 0.08333333
0.33333333 + (-0.20) = 0.13333333

我们回到A看看边界(0.08333333, 0.1333333)之间是否有元素。(0.11111111)落在该范围内,我们把B的第二个元素(2),并将其乘以其来自d的权重(1),并将其加到预期输出的第二个元素。
在对d中的所有元组进行迭代之后,预期输出的第四个元素计算如下:
下面是我尝试的代码:

D = np.zeros(len(A))
for v in d:
    weight, (_lower, _upper) = v
    lower, upper = A + _lower, A + _upper
    _A = np.tile(A, (len(A), 1))
    __A = np.bitwise_and(_A > lower.reshape(-1, 1), _A < upper.reshape(-1, 1))
    D += weight * (__A @ B)
D

希望这是有意义的。请随时提出澄清问题。谢谢!

6rqinv9w

6rqinv9w1#

因为区间(-0.25,-0.20),(-0.20,-0.10)和(-0.10,0.15)实际上是partition of an interval(-0.25,0.15)的子区间,你可以在元素应该插入A的地方插入find indices来保持顺序。它们指定slices of B to perform加法开。简而言之:

partition = np.array([-0.25, -0.20, -0.10, 0.15])
weights = np.array([1, 0.5, 2])
out = []
for n in A:
    idx = np.searchsorted(A, n + partition)
    results = np.add.reduceat(B[:idx[-1]], idx[:-1])
    out.append(np.dot(results, weights))
>>> print(out)
[7.5, 7.5, 8.0, 10.5, 12.0, 11.0, 11.5, 11.5, 6.5, 13.5, 27.5, 27.5, 31.5, 35.5, 37.5, 37.0, 36.0, 35.0, 34.0, 34.5, 34.0, 36.5, 33.0, 34.0, 34.5, 34.5, 36.0, 39.0, 37.0, 36.0, 37.0, 36.5, 37.5, 39.0, 36.5, 37.5, 34.0, 31.0, 27.5, 23.0]

请注意,如果B存在空切片,则results是错误的

相关问题