Числовой эквивалент list.index - PullRequest
17 голосов
/ 24 февраля 2011

В низкоуровневой функции, которая вызывается много раз, мне нужно сделать эквивалент списка python list.index, но с пустым массивом. Функция должна вернуться, когда найдет первое значение, и вызвать 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, как было предложено.

Ответы [ 6 ]

8 голосов
/ 24 февраля 2011

См. Мой комментарий к вопросу ОП для предостережений, но в целом я бы сделал следующее:

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, он относительно быстрый. Требование остановить поиск, когда он находит первое значение, может быть функционально неактуальным.

3 голосов
/ 10 ноября 2016

Если ваш массив 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
1 голос
/ 06 марта 2015

Вы можете кодировать его на 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
1 голос
/ 24 февраля 2011

Самое близкое, что я могу найти к тому, что вы просите, это ненулевое значение. Это может показаться странным, но из документации видно, что это может дать желаемый результат.

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) также может представлять интерес для вас.

0 голосов
/ 16 ноября 2015

Единственный раз, когда у меня возникла эта проблема, было достаточно преобразовать массив numpy в список:

a = numpy.arange(3)
print(list(a).index(2))

>>> 2
0 голосов
/ 23 августа 2011

NumPy's 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, вы можете обрабатывать это как хотите. Я понял из названия и намерения функции, что она останавливается после нахождения первого подходящего индекса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...