您的next 表达有效:
In [793]: [next((i for i,x in enumerate(row) if x),None) for row in np.eye(10)]
Out[793]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
好的,这给出了第一个非零的索引,但在我的示例中,这比 1 值更有趣。
In [801]: [row.nonzero()[0][0] for row in np.eye(10)]
Out[801]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
但是如果数组有一行全为0,比如in
arr =np.diag(np.arange(0,20,2))
nonzero 版本引发错误。需要对nonzero返回空列表的情况敏感。
要从idx 列表中获取值,请使用
arr[np.arange(len(idx)), idx]
时间
对于大型对角线数组,nonzero 明显更快:
In [822]: arr =np.diag(np.arange(1,2000,2))
In [823]: timeit idx = [next((i for i,x in enumerate(row) if x),None) for row in arr]
10 loops, best of 3: 87.6 ms per loop
In [824]: timeit [row.nonzero()[0][0] for row in arr]
100 loops, best of 3: 6.44 ms per loop
对于相同大小的数组,所有 1 都在行的开头,next 方法要快一些。
In [825]: arr = np.zeros_like(arr,int)
In [826]: arr[:,10]=1
In [827]: timeit idx = [next((i for i,x in enumerate(row) if x),None) for row in arr]
100 loops, best of 3: 3.61 ms per loop
In [828]: timeit [row.nonzero()[0][0] for row in arr]
100 loops, best of 3: 6.41 ms per loop
在 Python 中的短路循环与 C 代码中的完整循环之间存在权衡。
argmax 是另一种在每行中查找第一个非零索引的方法:
idx = np.argmax(arr>0, axis=1)
使用轴参数argmax 必须逐行迭代,然后在行内迭代,但它在编译代码中这样做。使用这样的布尔参数,argmax 会短路。我在另一个关于argmax(或最小值)和nan 值的问题中对此进行了探讨,这也是短路的。
https://stackoverflow.com/a/41324751/901925
另一种可能性(通灵@Divakar?)
def foo(arr):
I,J=np.where(arr>0)
u,i=np.unique(I,return_index=True)
return J[i]