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

Python 是否有一个NumPy函数来返回数组中某些内容的第一个索引?,python,arrays,numpy,numba,Python,Arrays,Numpy,Numba,我知道Python列表有一种方法可以返回某些内容的第一个索引: >>> l = [1, 2, 3] >>> l.index(2) 1 NumPy阵列是否也有类似的功能?NumPy中有许多操作可以组合在一起实现这一点。这将返回等于以下项的元素索引: numpy.nonzero(array - item) 然后,您可以获取列表中的第一个元素以获得单个元素。要根据任何条件建立索引,您可以执行以下操作: In [1]: from numpy import * In

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

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

NumPy阵列是否也有类似的功能?

NumPy中有许多操作可以组合在一起实现这一点。这将返回等于以下项的元素索引:

numpy.nonzero(array - item)

然后,您可以获取列表中的第一个元素以获得单个元素。

要根据任何条件建立索引,您可以执行以下操作:

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]

是的,给定要搜索的数组
array
,以及值
item
,您可以使用:

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

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

array[itemindex[0][0]][itemindex[1][0]]
将等于您的物品,因此:

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

如果你想用它作为其他东西的索引,如果数组是可广播的,你可以使用布尔索引;您不需要显式索引。做到这一点最简单的方法是简单地基于真值进行索引

other_array[first_array == item]
任何布尔运算都有效:

a = numpy.arange(100)
other_array[first_array > 50]
非零方法也采用布尔值:

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

两个零表示索引元组(假设第一个数组是1D),然后表示索引数组中的第一项。

如果您只需要第一次出现的一个值的索引,您可以使用
非零
(或者
其中的
,在本例中相当于相同的内容):

如果您需要多个值中的每个值的第一个索引,您显然可以重复上述操作,但有一个技巧可能更快。以下内容查找每个子序列的第一个元素的索引:

请注意,它可以找到3s子序列和8s子序列的开头:

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

因此,它与查找每个值的第一个匹配项略有不同。在您的程序中,您可以使用排序版本的
t
来获得您想要的:

>>> 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
arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)

它将打印1。

从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检查所有元素是否匹配。如果在数组的早期有匹配项,则生成器表达式会更快。

只需添加一个基于的非常高效且方便的替代项,以查找第一个索引:

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.
这非常快,可以很自然地处理多维数组:

这比使用
np.where
np.non-zero
的任何方法都要快得多


但是,也可以优雅地处理多维数组(您需要手动将其转换为元组并且它没有短路),但如果找不到匹配项,则会失败:

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

对于1D数组,我建议使用
np.flatnonzero(array==value)[0]
,这相当于
np.nonzero(array==value)[0][0]
np.where(array==value)[0]
,但避免了拆开一个1元素元组的麻烦。

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

我们可以安全地假设Python中的
index()
函数是在找到第一个匹配项后停止的,这会产生最佳的平均性能

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

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
nonzero
返回数组,因此需要选择第一个元素来获取索引

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
):


这是一个开放的市场

另请参见:

该软件包(免责声明,我是其作者)包含一个与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,并具有各种处理缺失值的方法。

注意:这是针对python 2.7版本的。

您可以使用lambda函数来处理该问题,它可以在NumPy数组和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]
获取筛选元素的第一个索引

对于Python3.6,使用

list(result)
而不是

result

对于一维排序的数组,使用返回NumPy整数(位置)的O(log(n))将更加简单和有效。比如说,

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
arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)
只需确保数组已经排序

还要检查是否返回索引i a
result[0]
list(result)
result
arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)
if arr[i] == 3:
    print("present")
else:
    print("not present")
arr = np.array([[1,4],
                 [2,3]])
print(arr)

...[[1,4],
    [2,3]]
 
 index_elements = []
 for i in np.ndindex(arr.shape):
     index_elements.append((arr[i],i))

 
 index_elements = dict(index_elements)
 index_elements[4] 
  
  ... (0,1)
  
new_array_of_indicies = []

for i in range(len(some_array)):
  if some_array[i] == some_value:
    new_array_of_indicies.append(i)
    
>>> np.argmax(np.array([1,2,3]) == 2)
1
>>> cuts = np.array([10, 50, 100])
>>> cuts_pad = np.array([*cuts, np.Infinity])
>>> x   = np.array([7, 11, 80, 443])
>>> bins = np.argmax( x[:, np.newaxis] < cuts_pad[np.newaxis, :], axis = 1)
>>> print(bins)
[0, 1, 2, 3]