在numpy中查找第一个非零行

时间:2019-07-07 22:51:17

标签: python numpy

假设我们有一个像a这样的数组,我们想在其中找到第一个非零行。 a可以很大,即单通道图像。

a = np.array([[0, 0, 0], [0, 0, 0], [0, 1, 0], [2, 3, 2]])

array([[0, 0, 0],
       [0, 0, 0],
       [0, 1, 0],
       [2, 3, 2]])

在numpy中最快,最优雅的方法是什么?

现在我正在这样做:

row_idx = np.argmin(np.sum(a, axis=1)==0)

3 个答案:

答案 0 :(得分:3)

这是一个非常快的方法(下面的pp),但仅适用于连续数组。它使用视图强制转换并利用了短路的优势。在下面的比较中,我自由地解决了其他答案,以便它们可以正确处理全零输入。

结果:

                                pp    galaxyan  WeNYoBen1  WeNYoBen2
contiguous small sparse   1.863220    1.465050   3.522510   4.861850
           large dense    2.086379  865.158230  68.337360  42.832701
                 medium   2.136710  726.706850  71.640330  43.047541
                 sparse  11.146050  694.993751  71.333189  42.406949
non cont.  small sparse   1.683651    1.516769   3.193740   4.017490
           large dense   55.097940  433.429850  64.628370  72.984670
                 medium  60.434350  397.200490  67.545200  51.276210
                 sparse  61.433990  387.847329  67.141630  45.788040

代码:

import numpy as np

def first_nz_row(a):
    if a.flags.c_contiguous:
        b = a.ravel().view(bool)
        res = b.argmax()
        return res // (a.shape[1]*a.itemsize) if res or b[res] else a.shape[0]
    else:
        b = a.astype(bool).ravel()
        res = b.argmax()
        return res // a.shape[1] if res or b[res] else a.shape[0]

def use_nz(a):
    b = np.nonzero(a)[0]
    return b[0] if b.size else a.shape[0]

def any_max(a):
    b = a.any(1)
    res = b.argmax()
    return res if res or b[res] else a.shape[0]

def max_max(a):
    b = a.max(1).astype(bool)
    res = b.argmax()
    return res if res or b[res] else a.shape[0]

from timeit import timeit


A = [np.random.uniform(-R, 1, (N,M)).clip(0,None)
     for R,N,M in [[100,2,2], [10,100,1000], [1000,100,1000], [10000,100,1000]]]
t = 10000*np.array(
    [[timeit(f, number=100) for f in (lambda: first_nz_row(a),
                                      lambda: use_nz(a),
                                      lambda: any_max(a),
                                      lambda: max_max(a))]
     for a in A] +
    [[timeit(f, number=100) for f in (lambda: first_nz_row(a),
                                      lambda: use_nz(a),
                                      lambda: any_max(a),
                                      lambda: max_max(a))]
     for a in [a[:,::2] for a in A]])

import pandas as pd
index = "dense medium sparse".split()
index = pd.MultiIndex([['contiguous', 'non cont.'], ['small', 'large'], index], [np.repeat((0,1),4), np.repeat((0,1,0,1,),(1,3,1,3)), np.r_[2, :3, 2, :3]])
t = pd.DataFrame(t, columns="pp galaxyan WeNYoBen1 WeNYoBen2".split(), index=index)
print(t)

答案 1 :(得分:1)

非零会发现所有项目都不为零,并返回行/列号

np.nonzero(a)[0][0]

2

答案 2 :(得分:0)

我会做什么

a.any(1).argmax()
2

a.max(1).astype(bool).argmax()
2