我想应用这样的函数:
s[i] = a*x[i] + (1 - a)*s[i-1]
其中s
和x
都是相同长度的数组。
我不想使用for循环,因为这些数组非常大(> 50 mil)。我试过做这样的事情
def f(a,x):
s = [0]*len(x)
s[i] = a*x[i] + (1 - a)*s[i-1]
return s
但当然i
未定义,所以这不起作用。
有没有办法使用map
或numpy.apply_along_axis
或其他一些矢量化方法执行此操作?
我没有遇到过将函数应用于数组的当前和前一个元素而不使用for循环的方法,这就是我想要了解的方法。
修改
要明确一点,这里的for循环实现有效,但我想避免
s = [0]*len(x)
a=0.45
for i in range(len(x)):
s[i] = a*x[i] + (1-a)*s[i-1]
s[0] = x[0] # reset value of s[0]
答案 0 :(得分:1)
正如我在answer to basically the same question写的那样,你不能:
除了明确的
for
循环外,没有其他方法(一般情况下)。 这是因为没有办法将这个任务并行化 行(因为每一行都依赖于其他行)。更难以实现的是,您可以轻松生成chaotic behavior,例如看似无辜的外观 logistic map:
x_{n+1} = r * x_n * (1 - x_{n-1})
。如果你设法找到一个关闭的话,你只能找到解决方法 形式,基本上消除了复发关系。但这必须 为每个复发关系做,我很确定你不是 甚至保证存在封闭的形式......
答案 1 :(得分:0)
你可以避免循环,尽管矢量化更像是“计算每个值的所有内容”。
import numpy as np
# Loop
def fun(x, a):
s = [0] * len(x)
for i in range(len(x)):
s[i] = a * x[i] + (1 - a) * s[i - 1]
s[0] = x[0]
return s
# Vectorized
def fun_vec(x, a):
x = np.asarray(x, dtype=np.float32)
n = np.arange(len(x))
p = a * (1 - a) ** n
# Trick from here: https://stackoverflow.com/q/49532575/1782792
pz = np.concatenate((np.zeros(len(p) - 1, dtype=p.dtype), p))
pp = np.lib.stride_tricks.as_strided(
pz[len(p) - 1:], (len(p), len(p)),
(p.strides[0], -p.strides[0]), writeable=False)
t = x[np.newaxis] * pp
s = np.sum(t, axis=1)
s[0] = x[0]
return s
x = list(range(1, 11))
a = 0.45
print(np.allclose(fun(x, a), fun_vec(x, a)))
# True
这种策略虽然采用O(n 2 )内存,但计算量更大。根据情况,由于并行性可以更快(我在TensorFlow中做了类似的事情以消除tf.while_loop
以取得巨大成功),但在这种情况下它实际上更慢:
x = list(range(1, 101))
a = 0.45
%timeit fun(x, a)
# 31 µs ± 85.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit fun_vec(x, a)
# 147 µs ± 2.42 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
所以,可以有一个非循环版本,但它更像是一种好奇心。