在一个被多次调用的低级函数中,我需要做相当于python的list.index,但是需要一个numpy数组。函数需要在找到第一个值时返回,否则引发ValueError。类似的东西:
>>> a = np.array([1, 2, 3])
>>> np_index(a, 1)
0
>>> np_index(a, 10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 10 not in array
如果可能的话,我想避免使用Python循环。 np.where
不是一个选项,因为它总是遍历整个数组;一旦找到第一个索引,我需要停止的东西。
编辑:与问题相关的一些更具体的信息。
大约90%的时间,我正在搜索的索引是数组的前1/4到1/2。因此,这里可能存在2-4倍的加速因素。其余10%的时间值都不在数组中。
我已经对事情进行了分析,对np.where
的调用是瓶颈,至少占总运行时间的50%。
提出ValueError
并不重要;它只需要返回一些显然表明该值不在数组中的东西。
我可能会按照建议在Cython中编写解决方案。
答案 0 :(得分:8)
请参阅我对OP的问题的评论,但总的来说,我会做以下事情:
import numpy as np
a = np.array([1, 2, 3])
np.min(np.nonzero(a == 2)[0])
如果您要查找的值不在数组中,则会得到ValueError
,原因如下:
ValueError: zero-size array to ufunc.reduce without identity
因为你试图获取空数组的最小值。
我会分析这段代码并查看它是否是一个真正的瓶颈,因为通常当numpy使用内置函数而不是显式python循环搜索整个数组时,它相对较快。当发现第一个值时,坚持停止搜索可能在功能上无关紧要。
答案 1 :(得分:3)
如果您的numpy数组是1d数组,可以尝试这样:
a = np.array([1, 2, 3])
print a.tolist().index(2)
>>> 1
如果不是1d,您可以搜索数组:
a = np.array([[1, 2, 3],[2,5,6],[0,0,2]])
print a[0,:].tolist().index(2)
>>> 1
print a[1,:].tolist().index(2)
>>> 0
print a[2,:].tolist().index(2)
>>> 2
答案 2 :(得分:1)
我能找到的最接近你要求的是非零。这可能听起来很奇怪,但是文档看起来可能会产生预期的结果。
http://www.scipy.org/Numpy_Example_List_With_Doc#nonzero
特别是这部分:
a.nonzero()
返回非零元素的索引。
有关完整文档,请参阅
numpy.nonzero
。另见
numpy.nonzero:等效函数
>>> from numpy import *
>>> y = array([1,3,5,7])
>>> indices = (y >= 5).nonzero()
>>> y[indices]
array([5, 7])
>>> nonzero(y) # function also exists
(array([0, 1, 2, 3]),)
您可能也对(http://www.scipy.org/Numpy_Example_List_With_Doc#where)感兴趣。
答案 3 :(得分:1)
您可以在Cython中编码,只需从Python脚本导入即可。无需将整个项目迁移到Cython中。
# paste into: indexing.pyx
def index(long[:] lst, long value):
cdef int i
for i in range(len(lst)):
if lst[i] == value:
return i
raise ValueError
# import in your .py code
import pyximport
pyximport.install()
from indexing import index
# example
from numpy import zeros
a = zeros(10**6, int)
a[-1] = 1
index(a, 1)
Wall time: 6.07 ms
999999
index(a, 0)
Wall time: 38.1 µs
0
答案 4 :(得分:0)
我遇到这个问题的唯一一次,将numpy数组转换为列表就足够了:
a = numpy.arange(3)
print(list(a).index(2))
>>> 2
答案 5 :(得分:-1)
NumPy的searchsorted与列表的索引非常相似,不同之处在于它需要一个排序的数组并且行为更加数字化。最大的区别在于您不需要精确匹配,并且可以从左侧或右侧开始搜索。请参阅以下示例以了解其工作原理:
import numpy as np
a = np.array([10, 20, 30])
a.searchsorted(-99) == a.searchsorted(0) == a.searchsorted(10)
# returns index 0 for value 10
a.searchsorted(20.1) == a.searchsorted(29.9) == a.searchsorted(30)
# returns index 2 for value 30
a.searchsorted(30.1) == a.searchsorted(99) == a.searchsorted(np.nan)
# returns index 3 for undefined value
对于最后一种情况,返回索引为3,您可以根据需要处理。我从找到第一个合适索引后停止的函数的名称和意图中收集。