计算1D numpy数组中的局部均值

Bor*_*rys 10 python arrays numpy mean scipy

我有1D NumPy数组如下:

import numpy as np
d = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])
Run Code Online (Sandbox Code Playgroud)

我想计算(1,2,6,7),(3,4,8,9)等的平均值.这涉及4个元素的平均值:两个连续元素和两个连续元素后面的5个位置.

我尝试了以下方法:

>> import scipy.ndimage.filters as filt
>> res = filt.uniform_filter(d,size=4)
>> print res
[ 1  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19]
Run Code Online (Sandbox Code Playgroud)

遗憾的是,这并没有给我预期的结果.我该怎么做?

ray*_*ica 11

您可以使用信号处理视角来处理此问题,而不是编制索引.您基本上使用7抽头内核执行输入信号的离散卷积,其中三个中心系数为0而四肢为1,并且由于您要计算平均值,因此需要将所有值乘以(1/4).但是,你不是在计算所有元素的卷积,但我们稍后会解决这个问题.一种方法是使用 scipy.ndimage.filters.convolve1d:

import numpy as np
from scipy.ndimage import filters
d = np.arange(1, 21, dtype=np.float)
ker = (1.0/4.0)*np.array([1,1,0,0,0,1,1], dtype=np.float)
out = filters.convolve1d(d, ker)[3:-3:2]
Run Code Online (Sandbox Code Playgroud)

因为你正在使用7抽头内核,卷积会将输出扩展到左边3和右边3,所以你需要确保裁剪出前三个元素.您还想跳过所有其他元素,因为卷积涉及滑动窗口,但您想要丢弃所有其他元素,以便获得所需的结果.

我们得到这个out:

In [47]: out
Out[47]: array([  4.,   6.,   8.,  10.,  12.,  14.,  16.])
Run Code Online (Sandbox Code Playgroud)

要仔细检查以确定我们是否有正确的结果,请尝试对每个元素进行一些示例计算.第一个元素等于(1+2+6+7)/4 = 4.第二个元素等于(3+4+8+9)/4 = 6,依此类推.


对于头痛较少的解决方案,请尝试numpy.convolve使用mode=valid标志.这样可以避免向左和向右切割额外的填充,但您仍然需要跳过其他所有元素:

import numpy as np
d = np.arange(1, 21, dtype=np.float)
ker = (1.0/4.0)*np.array([1,1,0,0,0,1,1], dtype=np.float)
out = np.convolve(d, ker, mode='valid')[::2]
Run Code Online (Sandbox Code Playgroud)

我们还得到:

In [59]: out
Out[59]: array([  4.,   6.,   8.,  10.,  12.,  14.,  16.])
Run Code Online (Sandbox Code Playgroud)

最后,如果你想索引,这样的东西就足够了:

length = len(d[6::2])
out = np.array([(a+b+c+e)/4.0 for (a,b,c,e) in zip(d[::2][:length], d[1::2][:length], d[5::2][:length], d[6::2])])
Run Code Online (Sandbox Code Playgroud)

我们得到:

In [69]: out
Out[69]: array([  4.,   6.,   8.,  10.,  12.,  14.,  16.])
Run Code Online (Sandbox Code Playgroud)

这真的很丑,但它确实有效.信号的总长度由每个窗口的末尾位于第7个索引的事实决定.包含这些索引的数组的长度决定了信号的最终长度.另外,请注意,对于窗口中的元素,可以通过跳过每个其他元素直到数组的末尾来找到它的下一个元素.总共有4个这样的序列,我们只是zip在这4个序列中,每个序列跳过其他所有元素,但是我们开始有一个偏移量.第一个序列从偏移0开始,下一个在1开始,下一个在5开始,下一个在6开始.我们收集这四个元素并对它们求平均值,然后跳过数组中的每一个直到我们完成.

顺便说一句,我还是更喜欢卷积.