python - 在 Python/Numpy 中实现具有不同系数的简单滤波器的有效方法

标签 python numpy scipy

我正在寻找一种有效的方法来实现一个简单的滤波器,该滤波器具有一个随时间变化的系数,并由与输入信号长度相同的向量指定。

以下是所需行为的简单实现:

def myfilter(signal, weights):
    output = np.empty_like(weights)
    val = signal[0]
    for i in range(len(signal)):
        val += weights[i]*(signal[i] - val)
        output[i] = val
    return output

weights = np.random.uniform(0, 0.1, (100,))
signal = np.linspace(1, 3, 100)
output = myfilter(signal, weights)

有没有办法使用 numpy 或 scipy 更有效地完成此操作?

最佳答案

您可以用循环的开销换取一些额外的操作:

import numpy as np

def myfilter(signal, weights):
    output = np.empty_like(weights)
    val = signal[0]
    for i in range(len(signal)):
        val += weights[i]*(signal[i] - val)
        output[i] = val
    return output

def vectorised(signal, weights):
    wp = np.r_[1, np.multiply.accumulate(1 - weights[1:])]
    sw = weights * signal
    sw[0] = signal[0]
    sws = np.add.accumulate(sw / wp)
    return wp * sws

weights = np.random.uniform(0, 0.1, (100,))
signal = np.linspace(1, 3, 100)
print(np.allclose(myfilter(signal, weights), vectorised(signal, weights)))

在我的机器上,矢量化版本快了好几倍。它使用递归方程的“封闭形式”解。

编辑:对于很长的信号/权重(例如 100,000 个样本),此方法由于溢出而不起作用。在这种情况下,您仍然可以使用以下技巧节省一点(在我的机器上节省 50% 以上),它的额外好处是您不需要求解递归公式,只需反转它。

from scipy import linalg

def solver(signal, weights):
    rw = 1 / weights[1:]
    v = np.r_[1, rw, 1-rw, 0]
    v.shape = 2, -1
    return linalg.solve_banded((1, 0), v, signal)

这个技巧利用了这样一个事实,即递归在形式上类似于只有一个非零下对角线的矩阵上的高斯消除。它依赖于专门从事这一工作的库函数。

事实上,我对此感到非常自豪。

关于python - 在 Python/Numpy 中实现具有不同系数的简单滤波器的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41884571/

相关文章:

python - 根据表面所包围的 3D 区域将表面分配给区域

python - 按日期和城市重新采样和聚合数据帧

python - 多线程模块比 python 中的多处理慢

python - os.walk 是否利用操作系统返回的文件类型来提高效率?

python - 每 2 个 Numpy 元素的加权平均值

python - np.solve() 但当 A(第一个矩阵)未知时

python - 由于一维尺寸更好,程序会吐出轴错误,是因为我最终混合了吗?

python - Scipy 错误地解决了矩阵的特征问题

python - 从 PubChem FTP 数据生成分子的二维图像

python - genfromtxt 创建元组的一维数组而不是二维数组