当结果依赖于前一个单元格时,如何将函数应用于数组的每个元素

时间:2015-12-30 07:20:05

标签: python arrays numpy

我有一个数组:

a = np.array([2,3,5,8,3,5])

计算数组的最有效(矢量化)方法是什么,每个结果元素都是(伪代码):

result[0] = a[0]
for i > 0:
    result[i] = result[i-1] + (a[i] - result[i-1]) * factor

我可以使用以下低效代码(因子= 0.5)执行此操作:

a = np.array([2,3,5,8,3,5])
result = np.array([a[0]])
for k in a[1:]:
   result = np.append(result, result[-1]+(k-result[-1])*0.5)

这种阻尼函数的结果是:

array([ 2.,  2.5,  3.75,  5.875,  4.4375,  4.71875])

2 个答案:

答案 0 :(得分:6)

你在Python中寻找Haskell的scanl1替代品(Haskell示例):

Prelude> scanl1 (\a  b -> a + (b - a) * 0.5) [2, 3, 5, 8, 3, 5]
[2.0,2.5,3.75,5.875,4.4375,4.71875]

itertools模块中有accumulate个功能:

In [1]: import itertools

In [2]: itertools.accumulate([2, 3, 5, 8, 3, 5], lambda a, b: a + (b - a) * 0.5)
Out[2]: <itertools.accumulate at 0x7f1fc1fc1608>

In [3]: list(itertools.accumulate([2, 3, 5, 8, 3, 5], lambda a, b: a + (b - a) * 0.5))
Out[3]: [2, 2.5, 3.75, 5.875, 4.4375, 4.71875]

使用NumPy,您可以使用numpy.ufunc.accumulate函数,但是,根据this answer,实现中存在一个错误,这就是我们应该使用强制转换的原因。不幸的是,我对NumPy不太熟悉,而且可能有更好的方法:

In [9]: import numpy as np

In [10]: uf = np.frompyfunc(lambda a, b: a + (b - a) * 0.5, 2, 1)

In [11]: uf.accumulate([2,3,5,8,3,5], dtype=np.object).astype(np.float)
Out[11]: array([ 2.     ,  2.5    ,  3.75   ,  5.875  ,  4.4375 ,  4.71875])

答案 1 :(得分:1)

我想发布@soon代码如何工作,或者如何使用reduce来实现它:

def scanl(f, v):
    return reduce(lambda (l, v1), v:(l+[f(v1, v)], f(v1, v)), v[1:],  ([v[0]], v[0]))[0]

>>> scanl(lambda a, b: a + (b - a) * 0.5,[2, 3, 5, 8, 3, 5])
[2, 2.5, 3.75, 5.875, 4.4375, 4.71875]

它不是最好的表现,也不是更好的表现,但会让你知道如何做到这一点。