首先,有不止一种方法可以做到这一点。
这不是最高效的速度,但使用scipy.ndimage.generic_filter 可以让您轻松地在移动窗口上应用任意 python 函数。
举个简单的例子:
result = scipy.ndimage.generic_filter(data, np.std, size=2*radius)
注意边界条件可以通过mode kwarg 来控制。
另一种方法是使用一些不同的跨步技巧来查看实际上是一个移动窗口的数组,然后沿最后一个轴应用np.std。 (注意:这取自我之前的答案之一:https://stackoverflow.com/a/4947453/325565)
def strided_sliding_std_dev(data, radius=5):
windowed = rolling_window(data, (2*radius, 2*radius))
shape = windowed.shape
windowed = windowed.reshape(shape[0], shape[1], -1)
return windowed.std(axis=-1)
def rolling_window(a, window):
"""Takes a numpy array *a* and a sequence of (or single) *window* lengths
and returns a view of *a* that represents a moving window."""
if not hasattr(window, '__iter__'):
return rolling_window_lastaxis(a, window)
for i, win in enumerate(window):
if win > 1:
a = a.swapaxes(i, -1)
a = rolling_window_lastaxis(a, win)
a = a.swapaxes(-2, i)
return a
def rolling_window_lastaxis(a, window):
"""Directly taken from Erik Rigtorp's post to numpy-discussion.
<http://www.mail-archive.com/numpy-discussion@scipy.org/msg29450.html>"""
if window < 1:
raise ValueError, "`window` must be at least 1."
if window > a.shape[-1]:
raise ValueError, "`window` is too long."
shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
strides = a.strides + (a.strides[-1],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
乍一看有点难以理解这里发生了什么。不要插入我自己的答案之一,但我不想重新输入解释,所以请看这里:https://stackoverflow.com/a/4924433/325565,如果您以前没有见过这些“跨步”技巧。
如果我们将时序与 100x100 随机浮点数组与 radius 为 5 进行比较,它比原始版本或 generic_filter 版本快约 10 倍。但是,您在此版本的边界条件上没有灵活性。 (这与您当前所做的相同,而 generic_filter 版本为您提供了很大的灵活性,但牺牲了速度。)
# Your original function with nested loops
In [21]: %timeit sliding_std_dev(data)
1 loops, best of 3: 237 ms per loop
# Using scipy.ndimage.generic_filter
In [22]: %timeit ndimage_std_dev(data)
1 loops, best of 3: 244 ms per loop
# The "stride-tricks" version above
In [23]: %timeit strided_sliding_std_dev(data)
100 loops, best of 3: 15.4 ms per loop
# Ophion's version that uses `np.take`
In [24]: %timeit new_std_dev(data)
100 loops, best of 3: 19.3 ms per loop
“stride-tricks”版本的缺点是,与“普通”跨步滚动窗口技巧不同,此版本确实制作副本,而且它远大于原始数组。如果您在大型阵列上使用它,您会遇到内存问题! (附带说明一下,就内存使用和速度而言,它基本上等同于 @Ophion 的答案。这只是做同样事情的不同方法。)