我需要根据邻居值和自身计算矩阵中最常见的元素。我找到了一个generic_filter函数,我用它来计算我想要的东西。所以这就是我如何为二维数组做到这一点
arr = np.array([
[1, 2, 4],
[5, 6, 7],
[2, 4, 4]
])
def most_frequent(arr):
def most_frequent(val):
return Counter(val).most_common(1)[0][0]
footprint = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
return ndimage.generic_filter(arr, most_frequent, footprint=footprint, mode='constant')
print most_frequent(arr)
这会让我回头
[[0 0 0]
[0 4 0]
[0 0 0]]
忽略边缘上的元素。如您所见,中间元素为4,因为这是邻居和值中最常见的元素。
最大的问题是我需要为3d矩阵做同样的事情。所以对于像这样的矩阵
arr = np.array([
[[1, 1], [2, 2], [4, 4]],
[[5, 5], [6, 6], [7, 7]],
[[2, 2], [4, 4], [4, 4]]
])
我希望到处都有[0, 0]
,中间有[4, 4]
。这与RuntimeError('filter footprint array has incorrect shape.')
失败。更糟糕的是,我怀疑我可以在这里使用generic_filter,因为文档说:
cval:scalar,optional如果模式为,则填充输入的过去边缘的值 “恒定”。
那么如何解决我的问题?
答案 0 :(得分:1)
这是一个完全向量化的解决方案。
首先做平坦的社区:
(n,m,_)=M.shape
(sn,sm,s2)=M.strides
newshape=(n-2,m-2,9,2)
newstrides=(sn,sm,2*s2,s2)
neighborhoods=np.lib.stride_tricks.as_strided(M,newshape,newstrides)
"""
array([[[[1, 1],
[2, 2],
[4, 1],
[1, 1],
[5, 5],
[6, 6],
[7, 7],
[2, 3],
[2, 2]],
[[2, 2],
[4, 1],
[1, 1],
[5, 5],
[6, 6],
[7, 7],
[2, 3],
[2, 2],
[4, 1]]]])
"""
然后你必须打包这两个组件才能使用{1}来处理1D数组。
假设np.unique
是int32,您可以通过视图执行此操作:
M.dtype
现在我们定义一个函数,该函数采用一维数组并根据packed_neighborhoods=np.ascontiguousarray(neighborhoods).view(int64)
In [5]: packed_neighborhoods.shape
Out[5]: (1, 2, 9, 1)
找到最常见的指数:
np.unique
将它应用于好轴:
def mostfreq(arr):
_,index,counts=unique(arr, return_index=True, return_counts=True)
return index[counts.argmax()]
结果包括其他指数。
ind2=apply_along_axis(mostfreq,2,packed_neighborhoods).squeeze()
但是你的解决方案目前具有相同的性能;(。
答案 1 :(得分:0)
我发现如何实现这一目标的一种方法是做类似
的事情def most_frequent(M):
x, y, _ = arr.shape
res = np.zeros((x - 2, y - 2, 2))
for i in xrange(1, x - 1):
for j in xrange(1, y - 1):
neighbors = [M[i - 1, j - 1], M[i - 1, j], M[i - 1, j + 1], M[i, j - 1], M[i, j], M[i, j + 1], M[i + 1, j - 1], M[i + 1, j], M[i + 1, j + 1]]
res[i - 1, j - 1] = Counter([tuple(_) for _ in neighbors]).most_common(1)[0][0]
return res
仍在寻找更好的解决方案(不涉及我的2个循环的解决方案)。