【问题标题】:Finding relative maximums of a 2-D numpy array查找二维 numpy 数组的相对最大值
【发布时间】:2015-05-09 21:19:02
【问题描述】:

我有一个二维 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

它运行良好,但令我惊讶的是,它并不比以前的版本更有效率!

问题是:有没有更聪明的方法来完成这项任务?

请注意,效率很重要,因为我有许多大型数组要处理。

欢迎提供任何线索。 :)

【问题讨论】:

标签: python arrays numpy


【解决方案1】:

试试这个:

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 是最混乱的位。它采用 2d 数组,并将其转换为 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(实际上,这是没有意义的;我们可以只创建一个,因为它们是相同的),它们只是i2 和i3 的索引的数组(0, 1,2,...,8 等一维,依此类推)。然后我们将这些乘以框大小,并添加相对最大索引,以获得绝对最大索引。
  • 然后我们将这些组合起来以获得与您相同的输出。请注意,如果将它们保存为数组,而不是创建元组,它会更快。

【讨论】:

  • 请注意,在对 ast 的调用中不需要反斜杠,因为它被括号括起来。
  • 是的 - 出于某种原因,我倾向于痴迷地在任何地方放置反斜杠,也许担心如果我不这样做,当我切换到需要它们的另一种语言时我会忘记。
  • 哇,大步走是关键!我必须更彻底地研究 Numpy。同时,我正在尝试了解您的代码逻辑
  • ,因为“i3 = i2.choose(np.rollaxis(i3r,-1))”行报告:ValueError: Need between 2 and (32) array objects (inclusive)。
  • 呸——我应该知道会出现无证限制。有关这一点的更多信息,请参阅stackoverflow.com/q/28931900/599265。我将尝试记录对 np.choose 的 NPY_MAXARGS 限制,因为它突然出现相当烦人。无论如何,修改后的版本更令人困惑,但应该可以工作。
猜你喜欢
  • 2021-04-26
  • 2014-06-28
  • 1970-01-01
  • 2017-04-03
  • 2018-04-10
  • 2015-04-06
  • 1970-01-01
  • 2022-01-09
  • 2018-06-27
相关资源
最近更新 更多