有没有一个Numpy函数返回数组中的东西的第一个索引?
我知道有一个Python列表返回的东西的第一个索引的方法
>>> l = list([1, 2, 3]) >>> l.index(2) 1
有没有像那样的数组?
是的,下面是给定一个Numpy数组,数组和要search的值的项目的答案。
itemindex = numpy.where(array==item)
结果是首先包含所有行索引的元组,然后是所有列索引。
例如,如果数组是两个维度,它包含您的项目在两个位置然后
array[itemindex[0][0]][itemindex[1][0]]
将等于你的物品,所以会
array[itemindex[0][1]][itemindex[1][1]]
numpy.where
如果你需要只有一个值的第一次出现的索引,那么你可以使用nonzero
值 (或者在这种情况下相当于相同的东西):
>>> 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
如果你需要多个值中的每一个的第一个索引,你可以重复做同样的事情,但有一个技巧可能会更快。 以下find每个子序列的第一个元素的索引:
>>> nonzero(r_[1, diff(t)[:-1]]) (array([0, 3, 5, 6, 7, 8]),)
注意它find了3s的两个子序列和8s的两个子序列的开始:
[1,1,2,2,3,8,3,8,8]
因此,与查找每个值的第一个匹配项稍有不同。 在你的程序中,你可能能够使用t
的sorting版本来得到你想要的:
>>> st = sorted(t) >>> nonzero(r_[1, diff(st)[:-1]]) (array([0, 3, 5, 7]),)
你也可以转换一个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。
如果你打算把它作为其他的索引,如果数组是可以广播的,你可以使用布尔值索引。 你不需要明确的索引。 要做到这一点绝对最简单的方法是简单地根据一个真值进行索引。
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),然后是索引数组中的第一个元素。
根据任何标准进行索引,您可以如下所示:
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()所做的事情,除非没有findexception,否则不会引发exception。 要小心 – 在大型数组上这可能非常慢。 如果你想把它作为一个方法来使用的话,你也许可以将它们应用到数组上。
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中有很多的操作,也许可以放在一起来完成这个。 这将返回元素的索引等于项目:
numpy.nonzero(array - item)
然后,您可以将列表的第一个元素获取一个元素。
只需要添加一个非常高效和方便的numba选项来find第一个索引:
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.
这是相当快的, 自然地处理multidimensional array :
>>> arr1 = np.ones((100, 100, 100)) >>> arr1[2, 2, 2] = 2 >>> index(arr1, 2) (2, 2, 2) >>> arr2 = np.ones(20) >>> arr2[5] = 10 >>> index(arr2, 2) (5,)
这可以比任何使用np.where
或np.nonzero
方法快得多 (因为它是短路操作)。
然而, np.argwhere
也可以优雅地处理multidimensional array(你需要手动把它转换成一个元组,而不是短路),但是如果找不到匹配就会失败:
>>> tuple(np.argwhere(arr1 == 2)[0]) (2, 2, 2) >>> tuple(np.argwhere(arr2 == 2)[0]) (5,)
对于一维数组,我推荐np.flatnonzero(array == value)[0]
,它等同于np.nonzero(array == value)[0][0]
和np.where(array == value)[0][0]
但避免拆箱1元素元组的丑陋。
l.index(x)
返回最小的i ,使得i是列表中第一个x的索引。
人们可以安全地假定Python中的index()
函数被实现,以便在find第一个匹配之后停止,并且这导致最佳的平均性能。
为了查找在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
一个可以使用第二个参数来返回一个特殊的值,如果没有find元素,例如
In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None)
在numpy( argmax
, where
和argmax
) where
还有其他的函数可以用来在数组中寻找一个元素,但是他们都有通过整个数组寻找所有事件的缺点,因此没有被优化用于寻找第一个元素。 还要注意, where
和nonzero
返回数组,所以你需要select第一个元素来获取索引。
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),)
时间比较
只需检查大数组,使用迭代器的解决scheme在search的项目位于数组的开头时会更快(在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
这是一个开放的Nuby Github问题 。
另请参阅: Numpy:快速find第一个索引值
从np.where()中select第一个元素的另一种方法是与枚举一起使用生成器expression式,例如:
>>> 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)
这种方法的优点是在find第一个匹配之后停止检查数组的元素,而np.where则检查所有匹配的元素。 如果在数组的早期匹配,则生成器expression式会更快。
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]
这个解决scheme具有向量化的性能,可以推广到ndarrays,并且有各种处理缺失值的方法。