如何在py3

时间:2016-08-17 12:58:11

标签: python-3.x numpy

我似乎无法找到如何对这个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.convolvepandas.rolling_apply,但无法正常使用。也许现在是时候学习c-extensions?

对于~500k元素的输入数组,将时间缩短为50..100ms会很棒。

@hpaulj在他的回答中询问了b[k] a[:k]的封闭表达。我不认为它存在,但我对它做了一些工作,确实发现封闭形式包含一堆Jacobsthal数字,正如@Divakar指出的那样。

这是一个封闭的表格:

closed form using Jn

J_n这里是Jacobsthal number,当像这样扩展它时:

J_n = (2^n - (-1)^n) / 3

最终会得到一个我可以想象使用矢量化实现的表达式......

closed expression for b_k

2 个答案:

答案 0 :(得分:0)

大多数numpy代码一次对整个数组进行操作。好吧,它在C代码中迭代,但缓冲的方式与首先使用哪个元素并不重要。

此处更改为b[2]会影响为b[3]计算的值,并会影响该行。

add.at和其他此类ufunc执行无缓冲计算。这允许您重复向一个元素添加一些值。在那种情况下我玩了一下,但到目前为止没有运气。

cumsumcumprod对于价值取决于早期问题的问题也很方便。

是否可以概括计算,以便根据所有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的功率并不好玩。

为了跟踪浮点噪声,需要一个迭代解决方案,这是你所拥有的。