我有一个二维 numpy 数组,可以分割为 64 个盒子(想想棋盘)。 目标是一个函数,它返回每个框中最大值的位置和值。像这样的东西:
FindRefs(array) --> [(argmaxX00, argmaxY00, Max00), ...,(argmaxX63, argmaxY63, Max63)]
其中 argmaxXnn 和 argmaxYnn 是整个数组(不是盒子)的索引,Maxnn 是每个数组中的最大值盒子。换句话说,
Maxnn = array[argmaxYnn,argmaxYnn]
我已经尝试了明显的“嵌套”解决方案:
def FindRefs(array):
Height, Width = array.shape
plumx = []
plumy = []
lum = []
w = int(Width/8)
h = int(Height/8)
for n in range(0,8): # recorrer boxes
x0 = n*w
x1 = (n+1)*w
for m in range(0,8):
y0 = m*h
y1 = (m+1)*h
subflatind = a[y0:y1,x0:x1].argmax() # flatten index of box
y, x = np.unravel_index(subflatind, (h, w))
X = x0 + x
Y = y0 + y
lum.append(a[Y,X])
plumx.append(X)
plumy.append(Y)
refs = []
for pt in range(0,len(plumx)):
ptx = plumx[pt]
pty = plumy[pt]
refs.append((ptx,pty,lum[pt]))
return refs
它有效,但既不优雅也不高效。 所以我尝试了这个更 pythonic 的版本:
def FindRefs(a):
box = [(n*w,m*h) for n in range(0,8) for m in range(0,8)]
flatinds = [a[b[1]:h+b[1],b[0]:w+b[0]].argmax() for b in box]
unravels = np.unravel_index(flatinds, (h, w))
ur = [(unravels[1][n],unravels[0][n]) for n in range(0,len(box))]
absinds = [map(sum,zip(box[n],ur[n])) for n in range(0,len(box))]
refs = [(absinds[n][0],absinds[n][1],a[absinds[n][1],absinds[n][0]]) for n in range(0,len(box))]
return refs
它工作正常,但令我惊讶的是,它并不比以前的版本更有效率!
问题是:有没有更聪明的方法来完成任务?
请注意,效率很重要,因为我有许多大型数组需要处理。
欢迎提供任何线索。 :)
最佳答案
试试这个:
from numpy.lib.stride_tricks import as_strided as ast
import numpy as np
def FindRefs3(a):
box = tuple(x/8 for x in a.shape)
z=ast(a, \
shape=(8,8)+box, \
strides=(a.strides[0]*box[0],a.strides[1]*box[1])+a.strides)
v3 = np.max(z,axis=-1)
i3r = np.argmax(z,axis=-1)
v2 = np.max(v3,axis=-1)
i2 = np.argmax(v3,axis=-1)
i2x = np.indices(i2.shape)
i3 = i3r[np.ix_(*[np.arange(x) for x in i2.shape])+(i2,)]
i3x = np.indices(i3.shape)
ix0 = i2x[0]*box[0]+i2
ix1 = i3x[1]*box[1]+i3
return zip(np.ravel(ix0),np.ravel(ix1),np.ravel(v2))
请注意,您的第一个 FindRefs 反转索引,因此对于元组 (i1,i2,v),a[i1,i2] 不会返回正确的值,而 a[i2,i1] 会。
下面是代码的作用:
- 它首先根据数组的大小计算每个框 (
box
) 所需的尺寸。请注意,这不会进行任何检查:您需要有一个可以被均匀划分为 8 x 8 网格的数组。 - 然后
z
和ast
是最困惑的部分。它采用二维数组,并将其转换为 4d 数组。 4d 数组具有维度 (8,8,box[0],box[1]),因此它允许您选择所需的框(前两个轴),然后选择框内的位置(后两个) .这让我们可以通过在最后两个轴上进行操作来一次处理所有框。 v3
为我们提供了最后一个轴上的最大值:换句话说,它包含每个框中每列的最大值。 i3r 包含框中哪一行包含该最大值的索引。v2
沿着它自己的最后一个轴取v3
的最大值,它现在正在处理框中的行:它取列最大值,并找到最大值它们,因此v2
是一个二维数组,其中包含每个框的最大值。 如果您想要的只是最大值,这就是您所需要的。i2
是盒子中保持最大值的列的索引。- 现在我们需要获取框中行的索引……这比较棘手。
i3r
包含框中每列最大值的行索引,但我们想要 i2 中指定的特定列的行。我们通过使用i2
从i3r
中选择一个元素来做到这一点,这给了我们i3
。 - 此时,
i2
和i3
是 8 x 8 数组,其中包含相对于每个框的最大值的行索引和列索引。我们想要绝对索引。所以我们创建了i2x
和i3x
(实际上,这是没有意义的;我们可以只创建一个,因为它们是相同的),它们只是索引的数组code>i2
和i3
是(一维中的 0,1,2,...,8 等,等等)。然后我们将这些乘以框大小,并添加相对最大索引,以获得绝对最大索引。 - 然后我们将这些组合起来以获得与您相同的输出。请注意,如果您将它们保存为数组,而不是制作元组,速度会快得多。
关于python - 查找二维 numpy 数组的相对最大值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28929791/