首页 文章

是否有NumPy函数返回数组中某些内容的第一个索引?

提问于
浏览
338

我知道Python列表有一种方法可以返回第一个索引:

>>> l = list([1, 2, 3])
>>> l.index(2)
1

NumPy数组有类似的东西吗?

13 回答

  • 4

    对于一维 sorted 数组,使用numpy.searchsorted返回NumPy整数(位置)会更加简单和有效O(log(n)) . 例如,

    arr = np.array([1, 1, 1, 2, 3, 3, 4])
    i = np.searchsorted(arr, 3)
    

    只需确保数组已经排序

    同时检查返回的索引i是否实际包含搜索的元素,因为searchsorted的主要目标是查找应插入元素以保持顺序的索引 .

    if arr[i] == 3:
        print("present")
    else:
        print("not present")
    
  • 60

    numpy_indexed包(免责声明,我是它的作者)包含了numpy.ndarray的矢量化等效list.index;那是:

    sequence_of_arrays = [[0, 1], [1, 2], [-5, 0]]
    arrays_to_query = [[-5, 0], [1, 0]]
    
    import numpy_indexed as npi
    idx = npi.indices(sequence_of_arrays, arrays_to_query, missing=-1)
    print(idx)   # [2, -1]
    

    该解决方案具有矢量化性能,推广到ndarray,并具有处理缺失值的各种方法 .

  • 3

    从np.where()中选择第一个元素的另一种方法是使用生成器表达式和枚举,例如:

    >>> import numpy as np
    >>> x = np.arange(100)   # x = array([0, 1, 2, 3, ... 99])
    >>> next(i for i, x_i in enumerate(x) if x_i == 2)
    2
    

    对于二维数组,可以这样做:

    >>> x = np.arange(100).reshape(10,10)   # x = array([[0, 1, 2,... 9], [10,..19],])
    >>> next((i,j) for i, x_i in enumerate(x) 
    ...            for j, x_ij in enumerate(x_i) if x_ij == 2)
    (0, 2)
    

    这种方法的优点是它在找到第一个匹配后停止检查数组的元素,而np.where检查所有元素是否匹配 . 如果数组中的早期匹配,则生成器表达式会更快 .

  • 14

    如果您打算将其用作其他内容的索引,则可以使用布尔索引(如果数组是可广播的);你不需要明确的指数 . 绝对最简单的方法是简单地根据真值进行索引 .

    other_array[first_array == item]
    

    任何布尔运算都有效:

    a = numpy.arange(100)
    other_array[first_array > 50]
    

    非零方法也需要布尔值:

    index = numpy.nonzero(first_array == item)[0][0]
    

    两个零用于索引的元组(假设first_array是1D),然后是索引数组中的第一个项 .

  • 9

    对于1D阵列,我建议使用 np.flatnonzero(array == value)[0] ,这相当于 np.nonzero(array == value)[0][0]np.where(array == value)[0][0] ,但避免了取消装箱1元素元组的丑陋 .

  • 2

    Note: this is for python 2.7 version

    您可以使用lambda函数来处理问题,并且 it works both on NumPy array and list.

    your_list = [11, 22, 23, 44, 55]
    result = filter(lambda x:your_list[x]>30, range(len(your_list)))
    #result: [3, 4]
    
    import numpy as np
    your_numpy_array = np.array([11, 22, 23, 44, 55])
    result = filter(lambda x:your_numpy_array [x]>30, range(len(your_list)))
    #result: [3, 4]
    

    你可以使用

    result[0]
    

    获取过滤元素的第一个索引 .

    对于python 3.6,请使用

    list(result)
    

    代替

    result
    
  • -1

    您还可以将NumPy数组转换为空中列表并获取其索引 . 例如,

    l = [1,2,3,4,5] # Python list
    a = numpy.array(l) # NumPy array
    i = a.tolist().index(2) # i will return index of 2
    print i
    

    它将打印1 .

  • 1

    要对任何条件进行索引,您可以执行以下操作:

    In [1]: from numpy import *
    In [2]: x = arange(125).reshape((5,5,5))
    In [3]: y = indices(x.shape)
    In [4]: locs = y[:,x >= 120] # put whatever you want in place of x >= 120
    In [5]: pts = hsplit(locs, len(locs[0]))
    In [6]: for pt in pts:
       .....:         print(', '.join(str(p[0]) for p in pt))
    4, 4, 0
    4, 4, 1
    4, 4, 2
    4, 4, 3
    4, 4, 4
    

    这里有一个快速的函数来执行list.index()所做的事情,除非没有找到它会引发异常 . 注意 - 这在大型阵列上可能非常慢 . 如果你宁愿将它作为一种方法使用,你可以将其修补到数组上 .

    def ndindex(ndarray, item):
        if len(ndarray.shape) == 1:
            try:
                return [ndarray.tolist().index(item)]
            except:
                pass
        else:
            for i, subarray in enumerate(ndarray):
                try:
                    return [i] + ndindex(subarray, item)
                except:
                    pass
    
    In [1]: ndindex(x, 103)
    Out[1]: [4, 0, 3]
    
  • 33

    l.index(x) 返回最小的i,使得i是列表中第一次出现x的索引 .

    可以安全地假设Python中的 index() 函数已经实现,以便在找到第一个匹配后停止,这样可以获得最佳的平均性能 .

    要查找在NumPy数组中第一次匹配后停止的元素,请使用迭代器(ndenumerate) .

    In [67]: l=range(100)
    
    In [68]: l.index(2)
    Out[68]: 2
    

    NumPy数组:

    In [69]: a = np.arange(100)
    
    In [70]: next((idx for idx, val in np.ndenumerate(a) if val==2))
    Out[70]: (2L,)
    

    请注意,如果找不到元素,则两个方法 index()next 都会返回错误 . 使用 next ,可以使用第二个参数在未找到元素的情况下返回特殊值,例如

    In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None)
    

    NumPy中有其他函数( argmaxwherenonzero ),可用于查找数组中的元素,但它们都有缺点,即遍历整个数组查找所有出现的内容,因此未针对查找所有实例进行优化 . 第一要素 . 另请注意 wherenonzero 返回数组,因此您需要选择第一个元素来获取索引 .

    In [71]: np.argmax(a==2)
    Out[71]: 2
    
    In [72]: np.where(a==2)
    Out[72]: (array([2], dtype=int64),)
    
    In [73]: np.nonzero(a==2)
    Out[73]: (array([2], dtype=int64),)
    

    时间比较

    只检查大型数组,当搜索项位于数组的开头时(使用IPython shell中的 %timeit ),使用迭代器的解决方案会更快:

    In [285]: a = np.arange(100000)
    
    In [286]: %timeit next((idx for idx, val in np.ndenumerate(a) if val==0))
    100000 loops, best of 3: 17.6 µs per loop
    
    In [287]: %timeit np.argmax(a==0)
    1000 loops, best of 3: 254 µs per loop
    
    In [288]: %timeit np.where(a==0)[0][0]
    1000 loops, best of 3: 314 µs per loop
    

    这是一个开放的NumPy GitHub issue .

    另见:Numpy: find first index of value fast

  • 6

    是的,这是给出NumPy数组 array 和值 item 的答案,用于搜索:

    itemindex = numpy.where(array==item)
    

    结果是一个元组,首先是所有行索引,然后是所有列索引 .

    例如,如果一个数组是两个维度,那么它包含您在两个位置的项目

    array[itemindex[0][0]][itemindex[1][0]]
    

    将等于你的项目,所以会

    array[itemindex[0][1]][itemindex[1][1]]
    

    numpy.where

  • 6

    NumPy中有许多操作可能可以组合起来完成此操作 . 这将返回等于item的元素索引:

    numpy.nonzero(array - item)
    

    然后,您可以使用列表的第一个元素来获取单个元素 .

  • 4

    如果你需要第一次出现 only one value 的索引,你可以使用 nonzero (或 where ,在这种情况下相同的东西):

    >>> t = array([1, 1, 1, 2, 2, 3, 8, 3, 8, 8])
    >>> nonzero(t == 8)
    (array([6, 8, 9]),)
    >>> nonzero(t == 8)[0][0]
    6
    

    如果你需要每个 many values 的第一个索引,你显然可以反复做同样的事情,但有一个技巧可能会更快 . 以下查找第一个的索引每个子序列的元素:

    >>> nonzero(r_[1, diff(t)[:-1]])
    (array([0, 3, 5, 6, 7, 8]),)
    

    请注意,它找到3的子序列的开始和8s的两个子序列:

    [ 1 ,1,1, 2 ,2, 3838 ,8]

    所以它与找到每个值的第一次出现略有不同 . 在您的程序中,您可以使用 t 的排序版本来获得您想要的内容:

    >>> st = sorted(t)
    >>> nonzero(r_[1, diff(st)[:-1]])
    (array([0, 3, 5, 7]),)
    
  • 413

    只是为了找到第一个索引,添加一个非常高效且方便的numba备选方案,基于np.ndenumerate

    from numba import njit
    import numpy as np
    
    @njit
    def index(array, item):
        for idx, val in np.ndenumerate(array):
            if val == item:
                return idx
        # If no item was found return None, other return types might be a problem due to
        # numbas type inference.
    

    这非常快,并且可以自然地处理多维数组:

    >>> arr1 = np.ones((100, 100, 100))
    >>> arr1[2, 2, 2] = 2
    
    >>> index(arr1, 2)
    (2, 2, 2)
    
    >>> arr2 = np.ones(20)
    >>> arr2[5] = 2
    
    >>> index(arr2, 2)
    (5,)
    

    这可能是 much faster (因为它使操作短路)比使用 np.wherenp.nonzero 的任何方法都要好 .


    但是np.argwhere也可以优雅地处理多维数组(你需要手动将它转换为元组 and 它没有短路)但是如果找不到匹配则会失败:

    >>> tuple(np.argwhere(arr1 == 2)[0])
    (2, 2, 2)
    >>> tuple(np.argwhere(arr2 == 2)[0])
    (5,)
    

相关问题