在二维布尔数组中查找最顶层True值索引的有效方法(Python)



假设我有一个形状为(nrows,ncols)的二维布尔数组。我试图有效地提取索引的最上面的True值为每列在数组中。如果列全部为False值,则不返回该列的索引。下面是形状为(4,6)的布尔数组的示例,其中粗体的下标为true将是期望的输出。

假假假假假假假假假

真正False FalseTrue假假

True FalseTrueFalse FalseTrue

真假真真假假假

期望输出值的指数(行,坳):[(1,0),(2,2),(1,3)(2、5)]

我试过用numpy。还有一个实现的天际线算法,但这两个选项都很慢。有没有更有效的方法来解决这个问题?

提前感谢您的帮助。

您可以使用np.argmax来检测True的前一个值

准备示例数组。

import numpy as np
a = np.array(
[[0,0,0,0,0,0],
[1,0,0,1,0,0],
[1,0,1,0,0,1],
[1,0,1,1,0,0]]).astype('bool')
a

输出
array([[False, False, False, False, False, False],
[ True, False, False,  True, False, False],
[ True, False,  True, False, False,  True],
[ True, False,  True,  True, False, False]])

堆叠一行False来处理没有True的列。在每个有np.argmax的列中找到第一个True,并为行索引添加一个排列。您必须通过-1调整列索引,因为我们向数组中添加了一行。然后选择True的索引大于0

的列。
b = np.vstack([np.zeros_like(a[0]),a])
t = b.argmax(axis=0)
np.vstack([t - 1, np.arange(len(a[0]))]).T[t > 0]

输出
array([[1, 0],
[2, 2],
[1, 3],
[2, 5]])

将@HenryYik答案翻译成numpy给出一行解决方案

np.vstack([a.argmax(axis=0), np.arange(len(a[0]))]).T[a.sum(0) > 0]

输出
array([[1, 0],
[2, 2],
[1, 3],
[2, 5]])

如果您愿意使用pandas,您可以构建df,只删除False列,然后idxmax:

arr = [[False, False, False, False, False, False],
[True, False, False, True, False, False],
[True, False, True, False, False, True],
[True, False, True, True, False, False]]
df = pd.DataFrame(arr, columns=range(len(arr[0])))
s = df.loc[:, df.sum()>0].idxmax()
print (s)

结果:

0    1
2    2
3    1
5    2
dtype: int64

这是colvalue vs row value。你可以把它转换回你想要的形式:

print (list(zip(s, s.index)))
[(1, 0), (2, 2), (1, 3), (2, 5)]

我建议你试试这个:

def get_topmost(ar: np.ndarray):
return [(row.index(True), i) for i, row in enumerate(ar.T.tolist()) if True in row]

示例:(should works as is)

>>> test = np.array([
[False, False, False, False, False, False],
[True,  False, False, True,  False, False],
[True,  False, True,  False, False, True],
[True,  False, True,  True,  False, False],
])
>>> print(get_topmost(test))
[(1, 0), (2, 2), (1, 3), (2, 5)]