Если вы ищете первую строку, в которой элемент существует в первом столбце, это работает (хотя это приведет к ошибке индекса, если ее не существует)rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
BrT
29
Что если вы хотите, чтобы он прекратил поиск после нахождения первого значения? Я не думаю, что где () сопоставим, чтобы найти ()
np.argwhereбыло бы немного более полезным здесь:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
Эрик
3
Стоит отметить, что этот ответ предполагает, что массив является 2D. whereработает с любым массивом и возвращает кортеж длины 3 при использовании на массиве 3D и т. д.
P. Camilleri
70
Если вам нужен индекс первого вхождения только одного значения , вы можете использовать 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
Если вам нужен первый индекс каждого из множества значений , вы, очевидно, можете делать то же самое, что и выше, но есть хитрость, которая может быть быстрее. Следующее находит индексы первого элемента каждой подпоследовательности :
Обратите внимание, что он находит начало как подпоследовательности 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]),)
@Geoff, r_объединяет; или, точнее, он переводит объекты среза в конкатенацию по каждой оси. Я мог бы использовать hstackвместо этого; это могло быть менее запутанным. См. Документацию для получения дополнительной информации о r_. Существует также c_.
Вебьорн Лёса
+1, приятный! (против NP.where) ваше решение намного проще (и, вероятно, быстрее) в случае, когда нам нужно только первое вхождение заданного значения в одномерном массиве
doug
3
Последний случай (поиск первого индекса всех значений) задаетсяvals, locs = np.unique(t, return_index=True)
askewchan
@askewchan ваша версия функционально эквивалентна, но намного, намного, намного медленнее
Дживан
50
Вы также можете преобразовать массив 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 2print i
Возможно, библиотека изменилась с момента ее написания. Но это было первое решение, которое сработало для меня.
amracel
1
Я хорошо использовал это, чтобы найти несколько значений в списке, используя понимание списка:[find_list.index(index_list[i]) for i in range(len(index_list))]
Мэтт Уэнам,
1
@MattWenham Если он достаточно большой, вы можете преобразовать find_listего в массив NumPy object(или что-то более конкретное, что подходит) и просто сделать find_arr[index_list].
Нарфанар
Абсолютно не по теме, но я впервые вижу фразу «в воздухе» - то, что я видел больше всего, на ее месте, вероятно, «на лету».
flow2k
18
Просто чтобы добавить очень производительный и удобный NumbaАльтернатива на основе np.ndenumerateпоиска первого индекса:
from numba import njit
import numpy as np
@njitdef 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.
Это довольно быстро и естественно работает с многомерными массивами :
Это может быть намного быстрее (потому что это закорачивает операцию), чем любой подход, использующий np.whereили np.nonzero.
Однако np.argwhereможет также изящно работать с многомерными массивами (вам нужно будет вручную привести его к кортежу, и он не будет закорочен), но он потерпит неудачу, если совпадение не найдено:
@njitэто сокращение, jit(nopython=True)т.е. функция будет полностью скомпилирована на лету во время первого запуска, так что вызовы интерпретатора Python будут полностью удалены.
Бартоло-Отрит
14
Если вы собираетесь использовать это как индекс для чего-то другого, вы можете использовать логические индексы, если массивы являются трансляционными; вам не нужны явные индексы. Абсолютно простой способ сделать это - просто индексировать на основе истинного значения.
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), а затем к первому элементу в массиве индексов.
l.index(x)возвращает наименьшее значение i , так что i является индексом первого появления x в списке.
Можно смело предположить, что index()функция в Python реализована так, что она останавливается после нахождения первого совпадения, и это приводит к оптимальной средней производительности.
Чтобы найти остановку элемента после первого совпадения в массиве 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возвращают массивы, поэтому вам нужно выбрать первый элемент, чтобы получить индекс.
Просто проверяя, что для больших массивов решение, использующее итератор, быстрее, когда искомый элемент находится в начале массива (используя %timeitв оболочке IPython):
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
Я думаю, что вы должны также указать время для наихудшего случая (последний элемент), чтобы читатели знали, что с ними происходит в худшем случае, когда они используют ваш подход.
MSeifert
@MSeifert Я не могу получить разумные сроки для решения итератора для наихудшего случая - я собираюсь удалить этот ответ, пока не
выясню
1
не %timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))работает? Если вам интересно, почему он работает в 1000 раз медленнее - это потому, что петли Python над массивами Numpy общеизвестно медленны.
Майферт
@MSeifert Нет, я не знал этого, но я также озадачен тем, что argmaxи whereв этом случае гораздо быстрее (поиск элемента в конце массива)
user2314737
Они должны быть такими же быстрыми, как если бы элемент находился в начале. Они всегда обрабатывают весь массив, поэтому они всегда занимают одно и то же время (по крайней мере, так и должно).
MSeifert
9
Для одномерных отсортированных массивов было бы намного проще и эффективнее O (log (n)) использовать numpy.searchsorted, который возвращает целое число NumPy (позиция). Например,
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
6
Для индексации по любым критериям вы можете сделать что-то вроде следующего:
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 >= 120In[5]: pts = hsplit(locs, len(locs[0]))In[6]:for pt in pts:.....:print(', '.join(str(p[0])for p in pt))4,4,04,4,14,4,24,4,34,4,4
И вот быстрая функция, чтобы сделать то, что делает list.index (), за исключением того, что не вызывает исключение, если оно не найдено. Осторожно - это, вероятно, очень медленно на больших массивах. Вы, вероятно, можете использовать это для массивов, если вы предпочитаете использовать его как метод.
def ndindex(ndarray, item):if len(ndarray.shape)==1:try:return[ndarray.tolist().index(item)]except:passelse:for i, subarray in enumerate(ndarray):try:return[i]+ ndindex(subarray, item)except:passIn[1]: ndindex(x,103)Out[1]:[4,0,3]
Для 1D массивов, я рекомендовал бы np.flatnonzero(array == value)[0], что эквивалентно , как np.nonzero(array == value)[0][0]и np.where(array == value)[0][0]но избегает уродства распаковки с 1-элементным кортежем.
Альтернативой выбору первого элемента из 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 for i, x_i in enumerate(x) if x_i == 2), None).
Эрленд Магнус Вигген
4
В NumPy существует множество операций, которые можно объединить для достижения этой цели. Это вернет индексы элементов, равные item:
numpy.nonzero(array - item)
Затем вы можете взять первые элементы списков, чтобы получить один элемент.
Ответы:
Да, вот ответ для массива NumPy
array
и значенияitem
для поиска:В результате получается кортеж с сначала всеми индексами строк, а затем всеми индексами столбцов.
Например, если массив имеет два измерения и содержит ваш элемент в двух местах, то
будет равна вашему предмету, и поэтому будет
numpy.where
источник
rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
np.argwhere
было бы немного более полезным здесь:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
where
работает с любым массивом и возвращает кортеж длины 3 при использовании на массиве 3D и т. д.Если вам нужен индекс первого вхождения только одного значения , вы можете использовать
nonzero
(илиwhere
, что в данном случае равно):Если вам нужен первый индекс каждого из множества значений , вы, очевидно, можете делать то же самое, что и выше, но есть хитрость, которая может быть быстрее. Следующее находит индексы первого элемента каждой подпоследовательности :
Обратите внимание, что он находит начало как подпоследовательности 3s, так и обеих подпоследовательностей 8s:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
Так что это немного отличается от поиска первого вхождения каждого значения. В вашей программе вы можете работать с отсортированной версией,
t
чтобы получить то, что вы хотите:источник
r_
такое?r_
объединяет; или, точнее, он переводит объекты среза в конкатенацию по каждой оси. Я мог бы использоватьhstack
вместо этого; это могло быть менее запутанным. См. Документацию для получения дополнительной информации оr_
. Существует такжеc_
.vals, locs = np.unique(t, return_index=True)
Вы также можете преобразовать массив NumPy в список и получить его индекс. Например,
Это напечатает 1.
источник
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
его в массив NumPyobject
(или что-то более конкретное, что подходит) и просто сделатьfind_arr[index_list]
.Просто чтобы добавить очень производительный и удобный NumbaАльтернатива на основе
np.ndenumerate
поиска первого индекса:Это довольно быстро и естественно работает с многомерными массивами :
Это может быть намного быстрее (потому что это закорачивает операцию), чем любой подход, использующий
np.where
илиnp.nonzero
.Однако
np.argwhere
может также изящно работать с многомерными массивами (вам нужно будет вручную привести его к кортежу, и он не будет закорочен), но он потерпит неудачу, если совпадение не найдено:источник
@njit
это сокращение,jit(nopython=True)
т.е. функция будет полностью скомпилирована на лету во время первого запуска, так что вызовы интерпретатора Python будут полностью удалены.Если вы собираетесь использовать это как индекс для чего-то другого, вы можете использовать логические индексы, если массивы являются трансляционными; вам не нужны явные индексы. Абсолютно простой способ сделать это - просто индексировать на основе истинного значения.
Любая логическая операция работает:
Ненулевой метод также принимает логические значения:
Два нуля относятся к кортежу индексов (при условии, что first_array равен 1D), а затем к первому элементу в массиве индексов.
источник
l.index(x)
возвращает наименьшее значение i , так что i является индексом первого появления x в списке.Можно смело предположить, что
index()
функция в Python реализована так, что она останавливается после нахождения первого совпадения, и это приводит к оптимальной средней производительности.Чтобы найти остановку элемента после первого совпадения в массиве NumPy, используйте итератор ( ndenumerate ).
Массив NumPy:
Обратите внимание, что оба метода
index()
иnext
возвращают ошибку, если элемент не найден. С помощьюnext
можно использовать второй аргумент для возврата специального значения в случае, если элемент не найден, например,Есть и другие функции в NumPy (
argmax
,where
иnonzero
) , которые могут быть использованы для поиска элемента в массиве, но все они имеют недостаток , проходящие через весь массив в поисках всех вхождений, таким образом , не оптимизирована для нахождения первого элемента. Обратите внимание, чтоwhere
иnonzero
возвращают массивы, поэтому вам нужно выбрать первый элемент, чтобы получить индекс.Сравнение времени
Просто проверяя, что для больших массивов решение, использующее итератор, быстрее, когда искомый элемент находится в начале массива (используя
%timeit
в оболочке IPython):Это открытая проблема NumPy GitHub .
Смотрите также: Numpy : быстро найти первый индекс значения
источник
%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))
работает? Если вам интересно, почему он работает в 1000 раз медленнее - это потому, что петли Python над массивами Numpy общеизвестно медленны.argmax
иwhere
в этом случае гораздо быстрее (поиск элемента в конце массива)Для одномерных отсортированных массивов было бы намного проще и эффективнее O (log (n)) использовать numpy.searchsorted, который возвращает целое число NumPy (позиция). Например,
Просто убедитесь, что массив уже отсортирован
Также проверьте, что возвращаемый индекс i действительно содержит искомый элемент, так как главная цель searchsorted - найти индексы, в которые должны быть вставлены элементы для поддержания порядка.
источник
Для индексации по любым критериям вы можете сделать что-то вроде следующего:
И вот быстрая функция, чтобы сделать то, что делает list.index (), за исключением того, что не вызывает исключение, если оно не найдено. Осторожно - это, вероятно, очень медленно на больших массивах. Вы, вероятно, можете использовать это для массивов, если вы предпочитаете использовать его как метод.
источник
Для 1D массивов, я рекомендовал бы
np.flatnonzero(array == value)[0]
, что эквивалентно , какnp.nonzero(array == value)[0][0]
иnp.where(array == value)[0][0]
но избегает уродства распаковки с 1-элементным кортежем.источник
Альтернативой выбору первого элемента из np.where () является использование выражения генератора вместе с перечислением, например:
Для двумерного массива можно сделать:
Преимущество этого подхода состоит в том, что он прекращает проверку элементов массива после того, как найдено первое совпадение, тогда как np.where проверяет все элементы на совпадение. Выражение генератора будет быстрее, если в массиве есть совпадение.
источник
None
как запасной вариант, он станетnext((i for i, x_i in enumerate(x) if x_i == 2), None)
.В NumPy существует множество операций, которые можно объединить для достижения этой цели. Это вернет индексы элементов, равные item:
Затем вы можете взять первые элементы списков, чтобы получить один элемент.
источник
Пакет numpy_indexed (заявление об отказе от ответственности, я его автор) содержит векторизованный эквивалент list.index для numpy.ndarray; это:
Это решение векторизовало производительность, обобщает до ndarrays и имеет различные способы обработки пропущенных значений.
источник
Примечание: это для версии Python 2.7
Вы можете использовать лямбда-функцию для решения проблемы, и она работает как с массивом, так и со списком NumPy.
И вы можете использовать
получить первый индекс отфильтрованных элементов.
Для Python 3.6 используйте
вместо
источник
<filter object at 0x0000027535294D30>
к Python 3 (проверено на Python 3.6.3). Возможно обновление для Python 3?