Is there a NumPy function to return the first index of something in an array?
我知道有一种方法可以让python列表返回某个内容的第一个索引:
1 2 3 | >>> l = [1, 2, 3] >>> l.index(2) 1 |
对于numpy数组有类似的东西吗?
是的,这里给出了一个numpy数组
1 | itemindex = numpy.where(array==item) |
。
结果是一个元组,首先是所有的行索引,然后是所有的列索引。
例如,如果一个数组是二维的,并且它在两个位置包含您的项,那么
1 | array[itemindex[0][0]][itemindex[1][0]] |
和你的物品一样
1 | array[itemindex[0][1]][itemindex[1][1]] |
。
麻木的地方
如果您只需要一个值的第一次出现的索引,您可以使用
1 2 3 4 5 | >>> 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 |
如果需要对多个值中的每一个进行第一个索引,显然可以重复执行上述操作,但有一个技巧可能更快。下面查找每个子序列的第一个元素的索引:
1 2 | >>> nonzero(r_[1, diff(t)[:-1]]) (array([0, 3, 5, 6, 7, 8]),) |
。
请注意,它找到3s子序列和8s子序列的开头:
[1、1、1、2、2、3、8、3、8、8]
所以它与查找每个值的第一次出现略有不同。在您的程序中,您可以使用经过排序的
1 2 3 | >>> st = sorted(t) >>> nonzero(r_[1, diff(st)[:-1]]) (array([0, 3, 5, 7]),) |
号
还可以将numpy数组转换为空气中的列表并获取其索引。例如,
1 2 3 4 | 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 | other_array[first_array == item] |
。
任何布尔运算都有效:
1 2 | a = numpy.arange(100) other_array[first_array > 50] |
非零方法也采用布尔值:
1 | index = numpy.nonzero(first_array == item)[0][0] |
。
这两个0表示索引的元组(假设第一个_数组是1d),然后是索引数组中的第一个项。
只需在
1 2 3 4 5 6 7 8 9 10 | 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. |
号
这非常快,可以很自然地处理多维数组:
1 2 3 4 5 6 7 8 9 10 11 | >>> 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,) |
号
这可能比使用
然而,
1 2 3 4 | >>> tuple(np.argwhere(arr1 == 2)[0]) (2, 2, 2) >>> tuple(np.argwhere(arr2 == 2)[0]) (5,) |
号
我们可以安全地假设在python中实现了
要查找numpy数组中第一个匹配后停止的元素,请使用迭代器(ndenumerate)。
1 2 3 4 | In [67]: l=range(100) In [68]: l.index(2) Out[68]: 2 |
numpy数组:
1 2 3 4 | In [69]: a = np.arange(100) In [70]: next((idx for idx, val in np.ndenumerate(a) if val==2)) Out[70]: (2L,) |
号
注意,如果找不到元素,两个方法
1 | In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None) |
numpy(
1 2 3 4 5 6 7 8 | 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中使用
1 2 3 4 5 6 7 8 9 10 | 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 |
这是一个开放的麻木的Github问题。
另请参见:numpy:快速查找第一个值索引
要对任何条件进行索引,可以执行如下操作:
1 2 3 4 5 6 7 8 9 10 11 12 | 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()所做的,除非没有找到异常就不会引发异常。小心——这在大型阵列上可能非常慢。如果您愿意将它用作一个方法,那么您可能需要将它修补到数组上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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] |
对于一维数组,我建议使用
对于一维排序数组,使用numpy.searchsorted将更简单和高效,它返回numpy整数(位置)。例如,
1 2 | arr = np.array([1, 1, 1, 2, 3, 3, 4]) i = np.searchsorted(arr, 3) |
。
只需确保数组已经排序
还要检查返回的索引i是否实际包含搜索的元素,因为SearchSorted的主要目标是找到应该在其中插入元素以保持顺序的索引。
1 2 3 4 | if arr[i] == 3: print("present") else: print("not present") |
号
在numpy中有许多操作可以组合在一起完成这一点。这将返回等于项的元素索引:
1 | numpy.nonzero(array - item) |
然后,您可以使用列表的第一个元素来获取单个元素。
从np.where()中选择第一个元素的替代方法是将生成器表达式与枚举一起使用,例如:
1 2 3 4 | >>> 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 |
号
对于二维数组,可以执行以下操作:
1 2 3 4 | >>> 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检查所有元素是否匹配。如果在数组的早期有匹配,生成器表达式将更快。
numpy_索引包(免责声明,我是其作者)包含numpy.ndarray的list.index的矢量化等价物;即:
1 2 3 4 5 6 | 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] |
。
此解决方案具有矢量化的性能,可归纳为ndarrays,并具有处理缺失值的各种方法。
注意:这是针对python 2.7版本的
您可以使用lambda函数来处理这个问题,它可以在numpy数组和list上工作。
1 2 3 4 5 6 7 8 | 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] |
。
你可以用
1 | result[0] |
以获取筛选元素的第一个索引。
对于python 3.6,使用
1 | list(result) |
。
而不是
1 | result |