Відповіді:
Так, ось відповідь, задана масивом NumPy array
, та значенням item
для пошуку:
itemindex = numpy.where(array==item)
Результат - кортеж спочатку всіх індексів рядків, а потім усіх індексів стовпців.
Наприклад, якщо масив має два виміри і він містив ваш елемент у двох місцях тоді
array[itemindex[0][0]][itemindex[1][0]]
було б дорівнює вашому товару, і так би
array[itemindex[0][1]][itemindex[1][1]]
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
, що в цьому випадку становить те саме):
>>> 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_
таке?
r_
конкатенати; або, точніше, він переводить об'єкти зрізів для об'єднання вздовж кожної осі. Я міг би використати hstack
натомість; які, можливо, були менш заплутаними. Дивіться документацію для отримання додаткової інформації про r_
. Також є c_
.
vals, locs = np.unique(t, return_index=True)
Ви також можете конвертувати масив 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.
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
масив NumPy object
(або щось більш конкретне, що підходить) і просто зробити find_arr[index_list]
.
Просто додати дуже ефектного та зручного numbaАльтернатива на основі np.ndenumerate
пошуку першого індексу:
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 були повністю видалені.
Якщо ви збираєтесь використовувати це як індекс в чомусь іншому, ви можете використовувати булові індекси, якщо масиви транслюються; вам не потрібні чіткі індекси. Абсолютний найпростіший спосіб зробити це - просто індексувати на основі значення істини.
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
поверніть масиви, тому вам потрібно вибрати перший елемент, щоб отримати індекс.
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),)
Просто перевірте, що для великих масивів рішення за допомогою ітератора відбувається швидше, коли шуканий елемент знаходиться на початку масиву (використовуючи %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
Це відкрите питання NumPy GitHub .
Дивіться також: Numpy : швидко знайдіть перший індекс вартості
%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))
працює? Якщо вам цікаво, чому це в 1000 разів повільніше - це тому, що петлі python над масивними масивами, як відомо, повільно.
argmax
і where
набагато швидше , в цьому випадку (пошук елемент в кінець масиву)
Для одновимірних відсортованих масивів було б набагато простіше та ефективніше 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")
Щоб індексувати будь-які критерії, ви можете зробити щось на зразок наступного:
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]
Альтернативою вибору першого елемента з 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)
.
У NumPy існує безліч операцій, які, можливо, можуть бути складені для цього. Це поверне індекси елементів, рівних позиції:
numpy.nonzero(array - item)
Потім ви можете взяти перші елементи списків, щоб отримати один елемент.
Пакет numpy_indexed (відмова, я його автор) містить векторизований еквівалент list.index для numpy.ndarray; це є:
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 і має різні способи боротьби з відсутніми значеннями.
Примітка: це для версії python 2.7
Ви можете використовувати лямбда-функцію для вирішення проблеми, і вона працює як у масиві 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
<filter object at 0x0000027535294D30>
на Python 3 (протестовано на Python 3.6.3). Можливо, оновлення для Python 3?