我有一个时间序列,需要递归处理以获得时间序列结果(分辨率)。这是我的示例代码:
res=s.copy()*0
res[1]=k # k is a constant
for i in range(2,len(s)):
res[i]=c1*(s[i]+s[i-1])/2 +c2*res[i-1]+c3*res[i-2]
其中c1,c2,c3是常数。它可以正常工作,但是我想使用向量化,并且尝试了以下方法:
res[2:]=c1*(s[2:]+s[1:-1])/2+c2*res[1:-1]+c3*res[0:-2]
但是我收到“ValueError:操作数不能与形状(1016)(1018)一起广播”
如果我尝试
res=c1*(s[2:]+s[1:-1])/2+c2*res[1:-1]+c3*res[0:-2]
没有给出任何错误,但是我没有得到正确的结果,因为在进行计算之前必须先对res [0]和res [1]进行初始化。
有办法用矢量化处理吗?
任何帮助将不胜感激,谢谢!
最佳答案
这个表达
res[i] = c1*(s[i] + s[i-1])/2 + c2*res[i-1] + c3*res[i-2]
说
res
是带有输入s
的线性滤波器(或ARMA进程)的输出。几个库具有用于对此进行计算的功能。这是使用scipy函数 scipy.signal.lfilter
的方法。通过检查递归关系,我们得到了滤波器传递函数的分子系数(
b
)和分母(a
):b = c1 * np.array([0.5, 0.5])
a = np.array([1, -c2, -c3])
我们还需要一个合适的初始条件
lfilter
来处理res[:2] == [0, k]
。为此,我们使用 scipy.signal.lfiltic
:zi = lfiltic(b, a, [k, 0], x=s[1::-1])
在最简单的情况下,可以这样调用
lfilter
:y = lfilter(b, a, s)
初始条件为
zi
,我们使用:y, zo = lfilter(b, a, s, zi=zi)
但是,为了完全匹配问题中提供的计算,我们需要输出
y
以[0, k]
开头。因此,我们将分配一个数组y
,使用[0, k]
初始化前两个元素,并将lfilter
的输出分配给y[2:]
:y = np.empty_like(s)
y[:2] = [0, k]
y[2:], zo = lfilter(b, a, s[2:], zi=zi)
这是带有原始循环和
lfilter
的完整脚本:import numpy as np
from scipy.signal import lfilter, lfiltic
c1 = 0.125
c2 = 0.5
c3 = 0.25
np.random.seed(123)
s = np.random.rand(8)
k = 3.0
# Original version (edited lightly)
res = np.zeros_like(s)
res[1] = k # k is a constant
for i in range(2, len(s)):
res[i] = c1*(s[i] + s[i-1])/2 + c2*res[i-1] + c3*res[i-2]
# Using scipy.signal.lfilter
# Coefficients of the filter's transfer function.
b = c1 * np.array([0.5, 0.5])
a = np.array([1, -c2, -c3])
# Create the initial condition of the filter such that
# y[:2] == [0, k]
zi = lfiltic(b, a, [k, 0], x=s[1::-1])
y = np.empty_like(s)
y[:2] = [0, k]
y[2:], zo = lfilter(b, a, s[2:], zi=zi)
np.set_printoptions(precision=5)
print "res:", res
print "y: ", y
输出为:
res: [ 0. 3. 1.53206 1.56467 1.24477 1.08496 0.94142 0.84605]
y: [ 0. 3. 1.53206 1.56467 1.24477 1.08496 0.94142 0.84605]
lfilter
接受axis
参数,因此您可以通过一次调用过滤信号数组。 lfiltic
没有axis
参数,因此设置初始条件需要循环。以下脚本显示了一个示例。import numpy as np
from scipy.signal import lfilter, lfiltic
import matplotlib.pyplot as plt
# Parameters
c1 = 0.2
c2 = 1.1
c3 = -0.5
k = 1
# Create an array of signals for the demonstration.
np.random.seed(123)
nsamples = 50
nsignals = 4
s = np.random.randn(nsamples, nsignals)
# Coefficients of the filter's transfer function.
b = c1 * np.array([0.5, 0.5])
a = np.array([1, -c2, -c3])
# Create the initial condition of the filter for each signal
# such that
# y[:2] == [0, k]
# We need a loop here, because lfiltic is not vectorized.
zi = np.empty((2, nsignals))
for i in range(nsignals):
zi[:, i] = lfiltic(b, a, [k, 0], x=s[1::-1, i])
# Create the filtered signals.
y = np.empty_like(s)
y[:2, :] = np.array([0, k]).reshape(-1, 1)
y[2:, :], zo = lfilter(b, a, s[2:], zi=zi, axis=0)
# Plot the filtered signals.
plt.plot(y, linewidth=2, alpha=0.6)
ptp = y.ptp()
plt.ylim(y.min() - 0.05*ptp, y.max() + 0.05*ptp)
plt.grid(True)
plt.show()
阴谋:
关于时间序列的python递归向量化,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21336794/