>>> l = [1, 2, 3]
>>> l.index(2)
1
NumPy数组是否有类似的东西?
#1 楼
是的,给定一个数组array
和一个值item
进行搜索,可以将np.where
用作:itemindex = numpy.where(array==item)
结果是一个元组,其中首先包含所有行索引,然后是所有列索引。
例如,如果一个数组是二维的,并且它在两个位置包含您的商品,那么
array[itemindex[0][0]][itemindex[1][0]]
将与您的商品相等,因此将是:
array[itemindex[0][1]][itemindex[1][1]]
评论
如果您正在寻找第一列中存在某项的第一行,则此行有效(尽管如果不存在则将引发索引错误)行,columns = np.where(array == item); first_idx = sorted([r代表r,c代表zip(行,列),如果c == 0])[0]
–BrT
2013年1月15日13:44
如果您希望它在找到第一个值后停止搜索该怎么办?我不认为where()可与find()相提并论
– Michael Clerx
2014年11月20日19:12
啊!如果您对性能感兴趣,请查看以下问题的答案:stackoverflow.com/questions/7632963/…
– Michael Clerx
2014年11月20日19:17
np.argwhere在这里会稍微有用:itemindex = np.argwhere(array == item)[0];数组[tuple(itemindex)]
–埃里克
16-10-17在20:46
值得注意的是,这个答案假设数组是2D的。 where可在任何数组上使用,在3D数组等上使用时将返回长度为3的元组。
– P. Camilleri
17年7月5日在7:52
#2 楼
如果仅需要一个值的第一次出现的索引,则可以使用nonzero
(或where
,在这种情况下,这意味着相同):>>> 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
如果您需要每个值的第一个索引,显然可以重复执行与上述相同的操作,但是有一个技巧可能会更快。以下内容查找每个子序列的第一个元素的索引:
>>> 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]
,所以它与查找每个值的第一个出现点略有不同。在您的程序中,您可能可以使用
t
的排序版本来获得所需的内容:>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)
评论
您能解释一下r_是什么吗?
– Geoff
11 Mar 23 '11 at 18:55
@Geoff,r_串联;或者,更准确地说,它可以将切片对象沿每个轴平移为串联。我本可以用hstack代替;可能会减少混乱。有关r_的更多信息,请参见文档。还有一个c_。
– Vebjorn Ljosa
2011年3月24日19:58
+1,不错! (与NP.where相比),如果它只是我们需要的一维数组中给定值的第一次出现,则您的解决方案要简单得多(并且可能更快)
– Doug
2014年2月14日的1:33
后一种情况(查找所有值的第一个索引)由vals给出,locs = np.unique(t,return_index = True)
– askewchan
2015年11月2日15:39
@askewchan您的版本在功能上是等效的,但是慢很多很多
–吉万
6月11日19:25
#3 楼
您还可以将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。
评论
自从第一次编写以来,库可能已更改。但这是第一个对我有用的解决方案。
– amracel
19年4月3日在19:20
我已经很好地利用它来使用列表理解来在列表中查找多个值:[find_list.index(index_list [i])for range in(len(index_list))]
–马特·温汉姆
19年4月29日在21:24
@MattWenham如果足够大,则可以将find_list转换为对象的NumPy数组(或者更合适的任何对象),然后执行find_arr [index_list]。
–纳凡纳尔
19年4月30日在9:33
完全是题外话,但这是我第一次看到“空中”一词-我所看到的最多的地方可能是“即时”。
– flow2k
19年11月28日在0:25
#4 楼
只是添加一个基于np.ndenumerate
的性能非常好用的numba替代项来找到第一个索引: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.nonzero
的任何方法都要快(因为它使操作短路)。但是
np.argwhere
也可以很好地处理多维数组(您需要手动将其强制转换为元组,并且不会短路),但是如果找不到匹配项,它将失败:>>> tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> tuple(np.argwhere(arr2 == 2)[0])
(5,)
评论
@njit是jit(nopython = True)的简写,即该函数将在第一次运行时即时进行完全编译,以便完全删除Python解释器调用。
–巴托洛-奥特里
18-10-2在7:22
由于版本至少为0.20.0,因此您也可以将其写为生成器,以便可以按需找到所有出现的特定值。
– norok2
10月28日16:32
#5 楼
如果要将其用作其他内容的索引,则可以使用布尔索引(如果数组是可广播的)。您不需要显式索引。做到这一点的最简单的方法是简单地基于真值编制索引。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),然后是第一个索引数组中的项目。
#6 楼
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
和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
),使用迭代器的解决方案会更快: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:快速找到价值的第一个索引
评论
我认为您还应该包括最坏情况(最后一个要素)的时间安排,以便读者了解在使用您的方法时最坏情况下发生的事情。
–MSeifert
17年5月12日14:08
@MSeifert对于最坏情况的迭代器解决方案,我无法获得合理的时间-我将删除此答案,直到我发现问题出在哪里
–user2314737
17年5月12日在14:51
%timeit next((idx为idx,np.ndenumerate(a)中的val,如果val == 99999)不起作用)吗?如果您想知道为什么它要慢1000倍,那是因为python在numpy数组上循环的速度非常慢。
–MSeifert
17年5月12日14:54
@MSeifert不,我不知道,但是我也为argmax和where在这种情况下更快(在数组末尾搜索元素)而感到困惑
–user2314737
17年5月12日在15:00
它们应该和元素开始时一样快。它们始终处理整个数组,因此它们总是花费相同的时间(至少应该这样做)。
–MSeifert
17年5月12日在15:02
#7 楼
对于一维排序的数组,使用numpy.searchsorted返回NumPy整数(位置)会更加简单和有效(O(log(n)))。例如,arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)
只需确保数组已经排序
还要检查返回的索引i是否实际上包含搜索到的元素,因为searchsorted的主要目标是找到应在其中插入元素以维持顺序的索引。
if arr[i] == 3:
print("present")
else:
print("not present")
评论
searchsorted不是nlog(n),因为它不会在搜索之前对数组进行排序,它假定参数数组已经排序。查看numpy.searchsorted的文档(上面的链接)
– Alok Nayak
18年8月7日在16:31
#8 楼
要根据任何条件建立索引,可以执行以下操作: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]
#9 楼
对于一维数组,我建议使用np.flatnonzero(array == value)[0]
,它与np.nonzero(array == value)[0][0]
和np.where(array == value)[0][0]
等效,但避免了将1元素元组拆箱的麻烦。#10 楼
从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将检查所有元素是否存在比赛。如果数组中的早期匹配项,则生成器表达式会更快。
评论
如果数组中可能根本没有匹配项,则此方法还可以让您方便地指定后备值。如果第一个示例返回None作为后备,它将成为next((i等于i,如果x_i == 2,则enumerate(x)中的x_i),无)。
–艾伦德·马格努斯·维格根(Erlend Magnus Viggen)
19年6月28日在8:46
#11 楼
NumPy中有很多操作可以组合在一起完成。这将返回等于item的元素的索引:numpy.nonzero(array - item)
然后可以使用列表的第一个元素来获得单个元素。
评论
会不会给出不等于item的所有元素的索引?
– Autoplectic
09年1月11日,下午2:06
#12 楼
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]
此解决方案具有矢量化性能,可推广到ndarrays,并具有多种处理缺失值的方法。
#13 楼
注意:这是针对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
评论
结果在Python 3上生成
– Peter Mortensen
18年6月26日在20:33
评论
仅供参考:一次获取NumPy数组中几个元素的索引