Як працює python numpy.where ()?


94

Я граюсь numpyі копаю документацію, і я натрапив на магію. А саме я говорю про numpy.where():

>>> x = np.arange(9.).reshape(3, 3)
>>> np.where( x > 5 )
(array([2, 2, 2]), array([0, 1, 2]))

Як вони внутрішньо досягають того, що ви можете передати щось x > 5на зразок методу? Я думаю, це має щось спільне, __gt__але я шукаю детального пояснення.

Відповіді:


75

Як вони внутрішньо досягають того, що ви можете передати щось на зразок x> 5 у метод?

Коротка відповідь - вони цього не роблять.

Будь-яка логічна операція над масивом numpy повертає логічний масив. (тобто __gt__, __lt__і т.д. всі повертають логічні масиви, де задана умова є істинною).

Напр

x = np.arange(9).reshape(3,3)
print x > 5

врожайність:

array([[False, False, False],
       [False, False, False],
       [ True,  True,  True]], dtype=bool)

Це та сама причина, чому щось подібне if x > 5:викликає ValueError, якщо xце масив numpy. Це масив значень True / False, а не одне значення.

Крім того, масиви numpy можна індексувати за допомогою булевих масивів. Наприклад , в цьому випадку x[x>5]врожайність [6 7 8].

Чесно кажучи, це досить рідко, що вам насправді потрібно, numpy.whereале він просто повертає індекси, де знаходиться логічний масив True. Зазвичай ви можете робити те, що вам потрібно, за допомогою простої булевої індексації.


10
Тільки для того, щоб зазначити, що numpy.whereу вас є 2 `` режими роботи '', перший повертає indices, де condition is Trueі якщо є необов'язкові параметри xта yвони присутні (та сама фігура condition, що може транслюватися до такої форми!), Він повертає значення, xколи condition is Trueінше з y. Отже, це робить whereбільш універсальним і дозволяє його частіше використовувати. Дякую
їжте

1
У деяких випадках також можуть бути накладні витрати, використовуючи __getitem__синтаксис []over numpy.whereабо numpy.take. Оскільки __getitem__він також повинен підтримувати нарізання, є деякі накладні витрати. Я бачив помітні різниці в швидкості при роботі зі структурами даних Python Pandas та логічному індексуванні дуже великих стовпців. У тих випадках, якщо вам не потрібна нарізка, тоді takeі whereнасправді краще.
ely,

24

Стара відповідь це заплутано. Це дає вам МІСЦЕ МІСЦЯ (всі вони) того, де ваш статус відповідає дійсності.

так:

>>> a = np.arange(100)
>>> np.where(a > 30)
(array([31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
       48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
       65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
       82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
       99]),)
>>> np.where(a == 90)
(array([90]),)

a = a*40
>>> np.where(a > 1000)
(array([26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
       43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
       60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
       77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
       94, 95, 96, 97, 98, 99]),)
>>> a[25]
1000
>>> a[26]
1040

Я використовую його як альтернативу list.index (), але він також має багато інших застосувань. Я ніколи не використовував його з двовимірними масивами.

http://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html

Нова відповідь Здається, людина запитувала щось більш фундаментальне.

Питання полягало в тому, як ВАС може реалізувати щось, що дозволяє функції (наприклад, де) знати, про що запитували.

Спочатку зауважимо, що виклик будь-якого з операторів порівняння робить цікаву справу.

a > 1000
array([False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True`,  True,  True,  True,  True,  True,  True,  True,  True,  True], dtype=bool)`

Це робиться шляхом перевантаження методу "__gt__". Наприклад:

>>> class demo(object):
    def __gt__(self, item):
        print item


>>> a = demo()
>>> a > 4
4

Як бачите, "a> 4" був дійсним кодом.

Ви можете отримати повний список та документацію щодо всіх перевантажених функцій тут: http://docs.python.org/reference/datamodel.html

Щось неймовірне - це те, наскільки просто це зробити. ВСІ операції в python виконуються таким чином. Вимовляння a> b еквівалентно a. gt (b)!


3
Це перевантаження оператора порівняння, схоже, не працює добре з більш складними логічними виразами - наприклад, я не можу зробити, np.where(a > 30 and a < 50)або np.where(30 < a < 50)це закінчується спробою оцінити логічне І двох масивів булевих значень, що є досить безглуздим. Чи є спосіб написати такий стан за допомогою np.where?
davidA

@meowsqueaknp.where((a > 30) & (a < 50))
тибальт

Чому np.where () повертає список у вашому прикладі?
Андреас Янкополус

0

np.whereповертає кортеж довжиною, рівний розмірності числового ndarray, для якого він викликається (іншими словами ndim), і кожен елемент кортежу є numpy ndarray індексів усіх тих значень у початковому ndarray, для яких умовою є True. (Будь ласка, не плутайте розмір з формою)

Наприклад:

x=np.arange(9).reshape(3,3)
print(x)
array([[0, 1, 2],
      [3, 4, 5],
      [6, 7, 8]])
y = np.where(x>4)
print(y)
array([1, 2, 2, 2], dtype=int64), array([2, 0, 1, 2], dtype=int64))


y - кортеж довжиною 2, оскільки x.ndimдорівнює 2. Перший елемент у кортежі містить номери рядків усіх елементів, більших за 4, а другий елемент містить номери стовпців усіх елементів, більших за 4. Як бачите, [1,2,2 , 2] відповідає номерам рядків 5,6,7,8, а [2,0,1,2] відповідає номерам стовпців 5,6,7,8. Зверніть увагу, що ndarray проходить по першому виміру (у рядку ).

Так само,

x=np.arange(27).reshape(3,3,3)
np.where(x>4)


поверне кортеж довжиною 3, оскільки x має 3 розміри.

Але зачекайте, там є ще щось для np.where!

при додаванні двох додаткових аргументів np.where; він виконає операцію заміни для всіх тих попарних комбінацій рядків і стовпців, які отримані вищевказаним кортежем.

x=np.arange(9).reshape(3,3)
y = np.where(x>4, 1, 0)
print(y)
array([[0, 0, 0],
   [0, 0, 1],
   [1, 1, 1]])
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.