我有一个非常大的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分钟才能完成。
是否有更好的方法对具有一定窗口大小的数组求和以加快速度?如果我将其转换为熊猫系列,也许可以在其中使用一些东西?
感谢您的帮助!
答案 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
(如果您可以在没有第一个值的情况下生活,请删除插入物...)