假设我有一个形状为(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)]