我知道Python列表有一个方法可以返回某个对象的第一个索引:

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

NumPy数组也有类似的东西吗?


当前回答

对于我的用例,我不能提前对数组排序,因为元素的顺序很重要。这是我的全部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)]

我认为它解释了重复值的无序数组。

其他回答

8种方法的比较

TL; diana:

(注:适用于100M元素以下的1d数组)

为了获得最佳性能,请使用index_of__v5 (numba + numpy. 5)。枚举+ for循环;参见下面的代码)。 如果numba不可用: 如果期望在前100k个元素中找到目标值,请使用index_of__v7 (for循环+枚举)。 否则使用index_of__v2/v3/v4 (numpy. exe)。Argmax或numpy。基于flatnonzero)。

由perfplot提供

import numpy as np
from numba import njit

# Based on: numpy.argmax()
# Proposed by: John Haberstroh (https://stackoverflow.com/a/67497472/7204581)
def index_of__v1(arr: np.array, v):
    is_v = (arr == v)
    return is_v.argmax() if is_v.any() else -1


# Based on: numpy.argmax()
def index_of__v2(arr: np.array, v):
    return (arr == v).argmax() if v in arr else -1


# Based on: numpy.flatnonzero()
# Proposed by: 1'' (https://stackoverflow.com/a/42049655/7204581)
def index_of__v3(arr: np.array, v):
    idxs = np.flatnonzero(arr == v)
    return idxs[0] if len(idxs) > 0 else -1


# Based on: numpy.argmax()
def index_of__v4(arr: np.array, v):
    return np.r_[False, (arr == v)].argmax() - 1


# Based on: numba, for loop
# Proposed by: MSeifert (https://stackoverflow.com/a/41578614/7204581)
@njit
def index_of__v5(arr: np.array, v):
    for idx, val in np.ndenumerate(arr):
        if val == v:
            return idx[0]
    return -1


# Based on: numpy.ndenumerate(), for loop
def index_of__v6(arr: np.array, v):
    return next((idx[0] for idx, val in np.ndenumerate(arr) if val == v), -1)


# Based on: enumerate(), for loop
# Proposed by: Noyer282 (https://stackoverflow.com/a/40426159/7204581)
def index_of__v7(arr: np.array, v):
    return next((idx for idx, val in enumerate(arr) if val == v), -1)


# Based on: list.index()
# Proposed by: Hima (https://stackoverflow.com/a/23994923/7204581)
def index_of__v8(arr: np.array, v):
    l = list(arr)
    try:
        return l.index(v)
    except ValueError:
        return -1

去Colab

注意:这是python 2.7版本

您可以使用lambda函数来处理这个问题,它既适用于NumPy数组,也适用于列表。

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

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中有很多操作可以放在一起来完成这个任务。这将返回等于item的元素的下标:

numpy.nonzero(array - item)

然后你可以取列表的第一个元素来得到一个元素。

只是添加一个非常高性能和方便的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,)

这比任何使用np的方法都要快得多(因为它使操作短路)。Where或np. non0。


然而np。Argwhere也可以优雅地处理多维数组(你需要手动将它转换为元组,而且不会短路),但如果没有找到匹配,它就会失败:

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