我很好奇是否有更优化的方法来计算这个“滚动加权和”(不确定实际术语是什么,但我将提供一个示例以进一步澄清)。我之所以问这个问题,是因为我确信我的当前代码片段在内存使用方面不是最优的,并且可以通过使用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)
范围内是否有任何元素。因为A
的第二个元素(0.11111111
)落在这个范围内,所以我们提取B
的第二个元素(2
),并将其乘以来自d
的权重(1
),然后加上期望输出的第二个元素。
在遍历d
中的所有元组之后,期望输出的第四个元素被计算为:
1 * 2 + 0.5 * 1 + 2 * (2 + 2) = 10.5
这是我的尝试代码:
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
希望这有意义。如有疑问,请随时提出。谢谢!
partition
和weights
,因为您所做的假设适用于我的问题。这也是一种更清洁的解决方案,可以降低内存成本。只是想知道,有没有什么方法可以使用numpy矢量化来避免在A
元素之间使用for
循环?谢谢! - Wilsonnp.add.reduceat
方法。通常,如果您能找到一种用扁平化数组替换命令的方法,就可以将for
循环向量化。for n in A: idx = np.searchsorted(A, n + partition)
部分很容易,您可以用np.searchsorted(A, partition + A[:, None])
替换它,并在需要时调用ravel
方法。我只是不知道该怎么处理这个np.add.reduceat
部分,它看起来很难在2D数组的轴上应用它。如果我有更多时间,我会再看看。 - mathfux