我知道Python列表有一个方法可以返回某个对象的第一个索引:
>>> xs = [1, 2, 3]
>>> xs.index(2)
1
NumPy数组也有类似的东西吗?
我知道Python列表有一个方法可以返回某个对象的第一个索引:
>>> xs = [1, 2, 3]
>>> xs.index(2)
1
NumPy数组也有类似的东西吗?
当前回答
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中还有其他函数(argmax, where和nonzero)可用于在数组中查找元素,但它们都有一个缺点,即遍历整个数组查找所有出现的元素,因此无法优化以查找第一个元素。还要注意,where和非零返回数组,因此需要选择第一个元素来获取索引。
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问题。
参见:Numpy:快速找到第一个值索引
其他回答
另一个之前没有提到的选项是bisect模块,它也适用于列表,但需要一个预先排序的列表/数组:
import bisect
import numpy as np
z = np.array([104,113,120,122,126,138])
bisect.bisect_left(z, 122)
收益率
3
Bisect还会在您要查找的数字在数组中不存在时返回一个结果,以便将该数字插入正确的位置。
numpy_indexed包(免责声明,我是它的作者)包含一个向量化的等效list。ndarray的索引;那就是:
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,并且有各种处理缺失值的方法。
对于我的用例,我不能提前对数组排序,因为元素的顺序很重要。这是我的全部numpy实现:
import numpy as np
# The array in question
arr = np.array([1,2,1,2,1,5,5,3,5,9])
# Find all of the present values
vals=np.unique(arr)
# Make all indices up-to and including the desired index positive
cum_sum=np.cumsum(arr==vals.reshape(-1,1),axis=1)
# Add zeros to account for the n-1 shape of diff and the all-positive array of the first index
bl_mask=np.concatenate([np.zeros((cum_sum.shape[0],1)),cum_sum],axis=1)>=1
# The desired indices
idx=np.where(np.diff(bl_mask))[1]
# Show results
print(list(zip(vals,idx)))
>>> [(1, 0), (2, 1), (3, 7), (5, 5), (9, 9)]
我认为它解释了重复值的无序数组。
您还可以将NumPy数组转换为list in - air并获取其索引。例如,
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。
找到了另一个循环解决方案:
new_array_of_indicies = []
for i in range(len(some_array)):
if some_array[i] == some_value:
new_array_of_indicies.append(i)