我正在计算2D numpy数组中较小块的聚合值。我想以一种有效的方式(而不是for和if语句)从聚合操作中排除值0。
我正在使用skimage.measure.block_reduce
和numpy.ma.masked_equal
,但似乎block_reduce
忽略了掩码。
import numpy as np
import skimage
a = np.array([[2,4,0,12,5,7],[6,0,8,4,3,9]])
zeros_included = skimage.measure.block_reduce(a,(2,2),np.mean)
包括0并(正确)产生
zeros_included
array([[3., 6., 6.]])
我希望
masked = np.ma.masked_equal(a,0)
zeros_excluded = skimage.measure.block_reduce(masked,(2,2),np.mean)
会成功的,但仍然会产生
zeros_excluded
array([[3., 6., 6.]])
所需的结果将是:
array([[4., 8., 6.]])
我正在寻找一种实现正确结果的pythonesque方式,使用skimage是可选的。当然,我实际的数组和块比该示例大得多,因此需要效率。
感谢您的关注。
答案 0 :(得分:1)
您可以使用np.nanmean
,但必须修改原始数组或创建一个新数组:
import numpy as np
import skimage
a = np.array([[2,4,0,12,5,7],[6,0,8,4,3,9]])
b = a.astype("float")
b[b==0] = np.nan
zeros_excluded = skimage.measure.block_reduce(b,(2,2), np.nanmean)
zeros_excluded
# array([[4., 8., 6.]])
答案 1 :(得分:0)
block_reduce
的核心代码是
blocked = view_as_blocks(image, block_size)
return func(blocked, axis=tuple(range(image.ndim, blocked.ndim)))
view_as_blocks
使用as_strided
创建数组的另一个视图:
In [532]: skimage.util.view_as_blocks(a,(2,2))
Out[532]:
array([[[[ 2, 4],
[ 6, 0]],
[[ 0, 12],
[ 8, 4]],
[[ 5, 7],
[ 3, 9]]]])
应用于蒙版数组时,它会产生相同的结果。实际上,它适用于masked.data
或np.asarray(masked)
。有些动作会保留子类,而不会。
In [533]: skimage.util.view_as_blocks(masked,(2,2))
Out[533]:
array([[[[ 2, 4],
[ 6, 0]],
...
这就是为什么将np.mean
应用于(2,3)轴时对屏蔽没有响应的原因。
np.mean
应用于被屏蔽的数组会将操作委托给数组自己的方法,因此对屏蔽敏感:
In [544]: np.mean(masked[:,:2])
Out[544]: 4.0
In [545]: masked[:,:2].mean()
Out[545]: 4.0
In [547]: [masked[:,i:i+2].mean() for i in range(0,6,2)]
Out[547]: [4.0, 8.0, 6.0]
np.nanmean
与view_as_blocks
一起使用,因为它不依赖于数组是特殊的子类。
我可以定义一个将遮罩应用于块视图的函数:
def foo(arr,axis):
return np.ma.masked_equal(arr,0).mean(axis)
In [552]: skimage.measure.block_reduce(a,(2,2),foo)
Out[552]:
masked_array(data=[[4.0, 8.0, 6.0]],
mask=[[False, False, False]],
fill_value=1e+20)
====
由于您的块不重叠,因此我将创建具有重塑和交换轴的块。
In [554]: masked.reshape(2,3,2).transpose(1,0,2)
Out[554]:
masked_array(
data=[[[2, 4],
[6, --]],
[[--, 12],
[8, 4]],
[[5, 7],
[3, 9]]],
mask=[[[False, False],
[False, True]],
[[ True, False],
[False, False]],
[[False, False],
[False, False]]],
fill_value=0)
,然后将mean
应用于最后两个轴:
In [555]: masked.reshape(2,3,2).transpose(1,0,2).mean((1,2))
Out[555]:
masked_array(data=[4.0, 8.0, 6.0],
mask=[False, False, False],
fill_value=1e+20)