我似乎无法找到如何对这个py3循环进行矢量化
import numpy as np
a = np.array([-72, -10, -70, 37, 68, 9, 1, -3, 2, 3, -6, -4, ], np.int16)
result = np.array([-72, -10, -111, -23, 1, -2, 1, -3, 1, 2, -5, -5, ], np.int16)
b = np.copy(a)
for i in range(2, len(b)):
b[i] += int( (b[i-1] + b[i-2]) / 2)
assert (b == result).all()
我尝试使用np.convolve
和pandas.rolling_apply
,但无法正常使用。也许现在是时候学习c-extensions?
对于~500k元素的输入数组,将时间缩短为50..100ms会很棒。
@hpaulj在他的回答中询问了b[k]
a[:k]
的封闭表达。我不认为它存在,但我对它做了一些工作,确实发现封闭形式包含一堆Jacobsthal数字,正如@Divakar指出的那样。
这是一个封闭的表格:
J_n
这里是Jacobsthal number,当像这样扩展它时:
J_n = (2^n - (-1)^n) / 3
最终会得到一个我可以想象使用矢量化实现的表达式......
答案 0 :(得分:0)
大多数numpy
代码一次对整个数组进行操作。好吧,它在C代码中迭代,但缓冲的方式与首先使用哪个元素并不重要。
此处更改为b[2]
会影响为b[3]
计算的值,并会影响该行。
add.at
和其他此类ufunc
执行无缓冲计算。这允许您重复向一个元素添加一些值。在那种情况下我玩了一下,但到目前为止没有运气。
cumsum
和cumprod
对于价值取决于早期问题的问题也很方便。
是否可以概括计算,以便根据所有b[i]
来定义a[:i]
。我们知道b[2]
是a[:2]
的函数,但b[3]
是什么?
即使我们将这个工作用于浮点数,也可能在执行整数除法时关闭。
答案 1 :(得分:0)
我认为你已经有了理智的解决方案。任何其他矢量化都依赖于浮点计算,并且很难跟踪误差累积。例如,假设你想要一个矩阵向量乘法:对于前七个项,矩阵看起来像
array([[ 1. , 0. , 0. , 0. , 0. , 0. , 0. ],
[ 0. , 1. , 0. , 0. , 0. , 0. , 0. ],
[ 0.5 , 0.5 , 1. , 0. , 0. , 0. , 0. ],
[ 0.25 , 0.75 , 0.5 , 1. , 0. , 0. , 0. ],
[ 0.375 , 0.625 , 0.75 , 0.5 , 1. , 0. , 0. ],
[ 0.3125 , 0.6875 , 0.625 , 0.75 , 0.5 , 1. , 0. ],
[ 0.34375, 0.65625, 0.6875 , 0.625 , 0.75 , 0.5 , 1. ]])
这种关系可以描述为迭代公式
[ a[i-2] ]
b[i] = [0.5 , 0.5 , 1] [ a[i-1] ]
[ a[i] ]
它定义了一系列带有
的单位矩阵形式的基本矩阵[0 ... 0.5 0.5 1 0 ... 0]
在第i行。并且连续乘法给出前七个项的矩阵。确实存在一个子对角线结构,但这些术语变得非常快。正如你所展示的那样,500k的功率并不好玩。
为了跟踪浮点噪声,需要一个迭代解决方案,这是你所拥有的。