Как я могу найти индекс первого вхождения числа в массиве Numpy? Для меня важна скорость. Меня не интересуют следующие ответы, потому что они сканируют весь массив и не останавливаются, когда находят первое вхождение:
itemindex = numpy.where(array==item)[0][0]
nonzero(array == item)[0][0]
Примечание 1. Ни один из ответов на этот вопрос не кажется релевантным. Существует ли функция Numpy для возврата первого индекса чего-либо в массиве?
Примечание 2: использование C-скомпилированного метода предпочтительнее цикла Python.
Хотя для вас уже слишком поздно, но для справки в будущем: использование numba ( 1 ) - самый простой способ, пока numpy не реализует его. Если вы используете дистрибутив anaconda python, он уже должен быть установлен. Код будет скомпилирован, так что все будет быстро.
а потом:
источник
xrange
необходимо заменить наrange
.enumerate
, как вfor i, v in enumerate(vec):
;if v == item: return i
. (Это не очень хорошая идея в Python <= 2.7, гдеenumerate
создается список, а не базовый итератор.)Я проверил несколько методов:
argwhere
nonzero
как в вопросе.tostring()
как в ответе @Rob ReilinkPython и Fortran кода доступны. Я пропустил бесперспективные, например преобразование в список.
Результаты в логарифмическом масштабе. Ось X - это положение стрелки (требуется больше времени, чтобы определить, находится ли она дальше по массиву); последнее значение - игла, которой нет в массиве. Ось Y - время найти его.
В массиве 1 миллион элементов, и тесты выполнялись 100 раз. Результаты все еще немного колеблются, но качественная тенденция очевидна: Python и f2py завершают работу на первом элементе, поэтому масштабируются по-разному. Python становится слишком медленным, если стрелка не находится в первых 1%, тогда как он
f2py
работает быстро (но вам нужно его скомпилировать).Подводя итог, f2py - самое быстрое решение , особенно если игла появляется довольно рано.
Он не встроен, что раздражает, но на самом деле это всего 2 минуты работы. Добавьте это в файл с именем
search.f90
:Если вы ищете что-то другое
integer
, просто измените тип. Затем скомпилируйте, используя:после чего вы можете сделать (из Python):
источник
f2py
1 элемент медленнее, чем 10?Вы можете преобразовать логический массив в строку Python, используя,
array.tostring()
а затем используя метод find ():Однако это подразумевает копирование данных, поскольку строки Python должны быть неизменными. Преимущество состоит в том, что вы также можете искать, например, нарастающий фронт, найдя
\x00\x01
источник
В случае сортированных массивов
np.searchsorted
работает.источник
Я думаю, вы столкнулись с проблемой, когда действительно помогли бы другой метод и некоторое априорное знание массива. То, что у вас есть X вероятность найти свой ответ в первых Y процентах данных. Разделение проблемы с надеждой на удачу, а затем выполнение этого на python с пониманием вложенного списка или что-то в этом роде.
Написание функции C для выполнения этой грубой силы также не так уж сложно с использованием ctypes .
Код C, который я взломал вместе (index.c):
и питон:
и я получаю 92.
Оберните питон в подходящую функцию, и готово.
Версия C намного (~ 20x) быстрее для этого семени (предупреждение, я не очень хорошо разбираюсь в timeit)
источник
@tal уже представил
numba
функцию для поиска первого индекса, но она работает только для одномерных массивов. С помощьюnp.ndenumerate
вы также можете найти первый индекс в массиве произвольной размерности:Пример кейса:
Тайминги показывают, что по производительности он похож на решение tals :
источник
array
прежде чем вводить ееnp.ndenumerate
, чтобы ваша ось интереса была первой.np.argwhere
) до 717 нс (ваше решение), как для массива формы(3000000, 12)
).Если ваш список отсортирован , вы можете добиться очень быстрого поиска по индексу с помощью пакета 'bisect'. Это O (log (n)) вместо O (n).
находит x в массиве a, что определенно быстрее в отсортированном случае, чем любая C-подпрограмма, проходящая через все первые элементы (для достаточно длинных списков).
Иногда полезно знать.
источник
>>> cond = "import numpy as np;a = np.arange(40)"
timeit("np.searchsorted(a, 39)", cond)
работает 3.47867107391 сек.timeit("bisect.bisect(a, 39)", cond2)
работает 7.0661458969116 секунд. Похоже,numpy.searchsorted
лучше для отсортированных массивов (по крайней мере, для целых).Насколько мне известно, закорочены только np.any и np.all на булевых массивах.
В вашем случае numpy должен дважды пройти через весь массив: один раз для создания логического условия и второй раз для поиска индексов.
Моя рекомендация в этом случае - использовать cython. Я думаю, что будет легко настроить пример для этого случая, особенно если вам не нужна большая гибкость для разных типов и форм.
источник
Мне это было нужно для работы, поэтому я изучил Python и интерфейс C Numpy и написал свой собственный. http://pastebin.com/GtcXuLyd Это только для одномерных массивов, но работает для большинства типов данных (int, float или strings), и тестирование показало, что он снова примерно в 20 раз быстрее, чем ожидаемый подход в чистом Python- тупой.
источник
Эта проблема может быть эффективно решена в чистом numpy путем обработки массива кусками:
Массив обрабатывается по размеру
step
. Чемstep
длиннее шаг, тем быстрее выполняется обработка обнуленного массива (худший случай). Чем он меньше, тем быстрее обрабатывается массив с ненулевым значением в начале. Уловка состоит в том, чтобы начать с малогоstep
и увеличивать его экспоненциально. Более того, нет необходимости увеличивать его выше некоторого порога из-за ограниченных преимуществ.Я сравнил решение с чистым решением ndarary.nonzero и numba с 10 миллионами массивов с плавающей запятой.
И результаты на моей машине:
Pure
ndarray.nonzero
определенно слабее. Решение numba в лучшем случае примерно в 5 раз быстрее. В худшем случае это примерно в 3 раза быстрее.источник
Если вы ищете первый ненулевой элемент, вы можете использовать следующий прием:
Это очень быстрое "безупречное" решение, но оно не работает в некоторых случаях, обсуждаемых ниже.
Решение использует тот факт, что почти все представление нуля для числовых типов состоит из
0
байтов. Это относится и к numpybool
. В последних версиях numpyargmax()
функция использует логику короткого замыкания при обработкеbool
типа. Размерbool
1 байт.Итак, нужно:
bool
. Копия не создаетсяargmax()
для поиска первого ненулевого байта с помощью логики короткого замыкания//
) смещения на размер одного элемента, выраженного в байтах (x.itemsize
)x[idx]
действительно ли ненулевое значение, чтобы определить случай, когда ненулевое значение отсутствуетЯ сделал несколько тестов против решения numba и построил его
np.nonzero
.Результат на моей машине:
Решение на 33% быстрее, чем numba, и оно "безупречно".
Недостатки:
object
float
илиdouble
вычисленииисточник
x
прежде чем звонитьnonzero()
. Вероятно, он будет медленнее, чем numba, но он ** не будет ** выполнять поиск по всему массиву при поиске первой нулевой записи, поэтому он может быть достаточно быстрым для ваших нужд.Как давний пользователь Matlab, я долгое время искал эффективное решение этой проблемы. Наконец, мотивированный обсуждениями предложений в этой ветке, я попытался предложить решение, реализующее API, аналогичный тому, что было предложено здесь , поддерживая на данный момент только одномерные массивы.
Вы бы использовали это так
Поддерживаются следующие операторы условий: cmp_equal, cmp_not_equal, cmp_larger, cmp_smaller, cmp_larger_eq, cmp_smaller_eq. Для эффективности расширение написано в c.
Вы можете найти исходный код, тесты и другие подробности здесь:
https://pypi.python.org/pypi?name=py_find_1st&:action=display
для использования в нашей команде (анаконда на linux и macos) Я сделал установщик анаконды, который упрощает установку, вы можете использовать его, как описано здесь
https://anaconda.org/roebel/py_find_1st
источник
Замечу, что если вы выполняете последовательность поисков, выигрыш в производительности от таких умных действий, как преобразование в строку, может быть потерян во внешнем цикле, если размер поиска недостаточно велик. Посмотрите, как производительность итерации find1, использующей предложенный выше трюк с преобразованием строк, и find2, использующей argmax вдоль внутренней оси (плюс корректировка, гарантирующая, что несоответствие возвращается как -1)
выходы
Тем не менее, находка, написанная на C, будет по крайней мере немного быстрее, чем любой из этих подходов.
источник
как насчет этого
источник
where(array==item)[0][0]
из вопроса ...Вы можете скрыть свой массив в
list
и использовать егоindex()
метод:Насколько мне известно, это метод, скомпилированный на C.
источник
timeit()
массив из 10000 целых чисел - преобразование в список было примерно в 100 раз медленнее! Я забыл, что основная структура данных для массива numpy очень отличается от списка ..