python numpy-有没有更快的卷积方法?

时间:2018-11-30 03:21:46

标签: python arrays numpy sum

我有一个非常大的numpy数组(一百万个整数)。我正在使用np.convolve来查找该数组的“最密集”区域。 “最小”区域是指固定长度的窗口,该窗口在求和时具有最高的数字。让我向您展示代码:

import numpy as np

example = np.array([0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,1,0,0,1,1,0,1,0,0,0,0,0,1,0])
window_size = 10
density = np.convolve(example, np.ones([window_size]), mode='valid')
print(density) 
# [7.0, 7.0, 8.0, 9.0, 9.0, 9.0, 8.0, 7.0, 6.0, 6.0, 5.0, 5.0, 5.0, 5.0, 4.0, 4.0, 4.0, 4.0, 4.0, 3.0, 3.0, 4.0, 3.0]

然后我可以使用np.argmax(density)来获取最高密度区域3的起始索引。

无论如何,在此示例中,它运行速度很快。但是当卷积超过一百万个元素数组且窗口大小为10,000时,需要2秒才能完成。如果我选择Windows_size为500,000,则需要3分钟才能完成。

是否有更好的方法对具有一定窗口大小的数组求和以加快速度?如果我将其转换为熊猫系列,也许可以在其中使用一些东西?

感谢您的帮助!

3 个答案:

答案 0 :(得分:5)

尝试使用scipy.signal.convolve。它具有使用快速傅立叶变换(FFT)计算卷积的选项,对于您提到的数组大小,它应该快得多。

使用长度为1000000的数组example并将其与长度为10000的数组进行卷积,np.convolve在我的计算机上花费了大约1.45秒,而scipy.signal.convolve用了22.7毫秒

答案 1 :(得分:1)

是如何使用内置的NumPy实数FFT函数对一维进行卷积:

import numpy, numpy.fft.fftpack_lite

def fftpack_lite_rfftb(buf, s):
    n = len(buf)
    m = (n - 1) * 2
    temp = numpy.empty(m, buf.dtype)
    numpy.divide(buf, m, temp[:n])
    temp[n:m] = 0
    return numpy.fft.fftpack_lite.rfftb(temp[:m], s)

def fftconvolve(x, y):
    xn = x.shape[-1]
    yn = y.shape[-1]
    cn = xn + yn - (xn + yn > 0)
    m = 1 << cn.bit_length()
    s = numpy.fft.fftpack_lite.rffti(m)  # Initialization; can be factored out for performance
    xpad = numpy.pad(x, [(0, 0)] * (len(x.shape) - 1) + [(0, m - xn)], 'constant')
    a = numpy.fft.fftpack_lite.rfftf(xpad, s)  # Forward transform
    ypad = numpy.pad(y, [(0, 0)] * (len(y.shape) - 1) + [(0, m - yn)], 'constant')
    b = numpy.fft.fftpack_lite.rfftf(ypad, s)  # Forward transform
    numpy.multiply(a, b, b)  # Spectral multiplication
    c = fftpack_lite_rfftb(b, s)  # Backward transform
    return c[:cn]

# Verify convolution is correct
assert (lambda a, b: numpy.allclose(fftconvolve(a, b), numpy.convolve(a, b)))(numpy.random.randn(numpy.random.randint(1, 32)), numpy.random.randn(numpy.random.randint(1, 32)))

请记住,这种填充对于大小明显不同(> 100%)的向量的卷积效率不高;您将需要使用诸如重叠加法的线性组合技术来进行较小的卷积。

答案 2 :(得分:1)

cumsum = np.cumsum(np.insert(example, 0, 0))

density2 = cumsum[window_size:]-cumsum[:-window_size]

np.all(density2 == density)

True

(如果您可以在没有第一个值的情况下生活,请删除插入物...)