我有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])
我想计算(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]
遗憾的是,这并没有给我预期的结果。我该怎么办?
答案 0 :(得分:11)
您可以使用信号处理视角来处理此问题,而不是建立索引。您基本上使用7抽头内核执行discrete convolution输入信号,其中三个中心系数为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]
因为你正在使用7抽头内核,卷积会将输出扩展3到左边,3扩展到右边,所以你需要确保裁掉第一个和最后三个元素。你还想跳过所有其他元素,因为卷积涉及一个滑动窗口,但你想丢弃所有其他元素,以便得到你想要的结果。
我们为out
得到了这个:
In [47]: out
Out[47]: array([ 4., 6., 8., 10., 12., 14., 16.])
要仔细检查我们是否有正确的结果,请尝试对每个元素进行一些示例计算。第一个元素等于(1+2+6+7)/4 = 4
。第二个元素等于(3+4+8+9)/4 = 6
,依此类推。
对于头痛较少的解决方案,请尝试使用mode=valid
标记的numpy.convolve
。这样可以避免向左和向右切掉额外的填充,但是你仍然需要跳过其他所有元素:
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]
我们也得到:
In [59]: out
Out[59]: array([ 4., 6., 8., 10., 12., 14., 16.])
最后,如果你想要建立索引,这样的事情就足够了:
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])])
我们得到:
In [69]: out
Out[69]: array([ 4., 6., 8., 10., 12., 14., 16.])
这真的很丑,但它确实有效。信号的总长度由每个窗口的末尾位于第7个索引的事实决定。包含这些索引的数组的长度决定了信号的最终长度。另外,请注意,对于窗口中的元素,可以通过跳过每个其他元素直到数组的末尾来找到它的下一个元素。总共有4个这样的序列,我们简单地zip
超过这4个序列,其中每个序列跳过其他所有元素,但是我们开始有一个偏移量。第一个序列从偏移0开始,下一个从1开始,下一个在5开始,下一个在6开始。我们收集这四个元素并对它们求平均值,然后跳过数组中的每个元素直到我们完成。
答案 1 :(得分:1)
您可以使用numpy.lib.stride_tricks.as_strided()
获取适用于更通用案例的分组数组:
import numpy as np
from numpy.lib.stride_tricks import as_strided
d = np.arange(1, 21)
consec = 2
offset = 5
nsub = 2
pace = 2
s = d.strides[0]
ngroups= (d.shape[0] - (consec + (nsub-1)*offset - 1))//pace
a = as_strided(d, shape=(ngroups, nsub, consec),
strides=(pace*s, offset*s, 1*s))
其中:
consec
是子组中连续数字的数量offset
每个子组中第一个条目之间的偏移量nsub
子组数量1, 2
是一个子组,与第二个子组6, 7
分开offset
pace
表示两个小组的第一个条目之间的步幅,在您的情况下为pace=consec
,但在更一般的情况下可能有所不同在您的情况下(使用给定的值)a
将是:
array([[[ 1, 2],
[ 6, 7]],
[[ 3, 4],
[ 8, 9]],
[[ 5, 6],
[10, 11]],
[[ 7, 8],
[12, 13]],
[[ 9, 10],
[14, 15]],
[[11, 12],
[16, 17]],
[[13, 14],
[18, 19]]])
通过以下方式准备好从中获得所需的平均值:
a.mean(axis=-1).mean(axis=-1)
#array([ 4., 6., 8., 10., 12., 14., 16.])