6.12. Вибірка та впорядкування¶
Редукції згортали масив до скаляра або результату нижчого рангу. Вибірка охоплює операції, що визначають які елементи залишаються та де вони опиняються: умовний вибір, обрізання, сортування, пошук індексів, перевпорядкування вздовж осі.
6.12.1. Умовний вибір¶
where() повертає масив, що приймає елементи з x там, де умова істинна, і з y в іншому випадку. Три операнди транслюються разом:
a = np.array([1, 2, 3, 4, 5], dtype=np.float)
np.where(a < 3, a, 0.0)
# array([1.0, 2.0, 0.0, 0.0, 0.0])
Це правильний інструмент для «if/else на кожен елемент» без написання циклу Python.
clip() є скороченням для maximum(lo, minimum(a, hi)) – насичення значень до діапазону:
np.clip(a, 2.0, 4.0)
# array([2.0, 2.0, 3.0, 4.0, 4.0])
maximum() і minimum() приймають два операнди і повертають поелементний більший / менший:
np.maximum(a, 3.0)
np.minimum(a, np.array([5, 4, 3, 2, 1]))
6.12.2. Пошук індексів¶
nonzero() повертає координати кожного ненульового елемента, розділені на один масив індексів на вимір. Для двовимірного вхідного масиву результат — це кортеж з двох масивів: перший містить індекси рядків, другий — індекси стовпців. Попарне зіставлення дає (row, col) кожної ненульової позиції:
m = np.array([[0, 2, 0],
[3, 0, 0]], dtype=np.float)
np.nonzero(m)
# (array([0, 1], dtype=uint16), array([1, 0], dtype=uint16))
Ненульові записи в m: m[0, 1] = 2 і m[1, 0] = 3. Перший повернутий масив [0, 1] містить їхні індекси рядків; другий [1, 0] – індекси стовпців. Читаючи обидва масиви поряд, отримуємо позиції (0, 1) і (1, 0).
Дві редукції також повертають індекси:
argmin()/argmax()– індекс найменшого / найбільшого елемента.argsort()– цілочисельний масив, що відсортував би вхідний масив вздовж заданої осі (за замовчуванням — остання):a = np.array([40, 10, 30, 20], dtype=np.uint8) idx = np.argsort(a) # array([1, 3, 2, 0], dtype=uint16) a[idx] # array([10, 20, 30, 40])
argsortзавжди повертаєuint16; сортований масив тому не повинен мати більше 65 535 елементів по осі сортування.
bincount() підраховує кількість входжень кожного невід’ємного цілого числа у одновимірному вхідному масиві типу uint8 / uint16
histogram = np.bincount(np.array([0, 1, 1, 2, 2, 2], dtype=np.uint8))
# array([1, 2, 3], dtype=uint16)
Корисно для побудови гістограм значень пікселів малих цілих чисел без написання циклу Python.
6.12.3. Сортування та впорядкування¶
sort() повертає відсортовану копію масиву вздовж заданої осі (за замовчуванням — остання). Для сортування на місці використовуйте sort() безпосередньо на масиві:
np.sort(np.array([3, 1, 2], dtype=np.float))
# array([1.0, 2.0, 3.0])
flip() обертає порядок вздовж заданої осі (по всіх осях, якщо axis не вказано):
np.flip(np.array([1, 2, 3, 4]))
# array([4, 3, 2, 1])
roll() циклічно зміщує елементи на задану кількість позицій. Корисно для реалізації кільцевого буфера у стилі регістра зсуву:
np.roll(np.array([1, 2, 3, 4]), 1)
# array([4, 1, 2, 3])
take() — явна форма індексування довільних позицій – вибір елементів за довільними індексами:
a = np.array([10, 20, 30, 40, 50], dtype=np.uint8)
np.take(a, [0, 2, 4])
# array([10, 30, 50], dtype=uint8)
6.12.4. Фільтрація та структурні зміни¶
compress() — явна форма булевого індексування – повертає зрізи a, вибрані булевою умовою:
a = np.array([10, 20, 30, 40], dtype=np.uint8)
np.compress(a > 15, a)
# array([20, 30, 40], dtype=uint8)
delete() повертає копію з видаленими записами за вказаними індексами:
a = np.array([10, 20, 30, 40, 50], dtype=np.uint8)
np.delete(a, [1, 3])
# array([10, 30, 50], dtype=uint8)
diff() повертає n-ту дискретну пряму різницю масиву вздовж осі. Використовується для обчислення змін першого порядку між сусідніми відліками:
samples = np.array([1, 3, 6, 10, 15], dtype=np.float)
np.diff(samples)
# array([2.0, 3.0, 4.0, 5.0])
6.12.5. Вартість кожної операції¶
Майже кожна функція на цій сторінці повертає щойно виділений масив. Два винятки:
sort()сортує на місці; вільна функціяsort()повертає відсортовану копію.take()приймає ключове словоout=для запису в уже існуючий буфер.
У циклі, що виконується багато разів на секунду, надавайте перевагу sort() на місці та повторно використовуйте заздалегідь виділені буфери скрізь. Булеві маски самі виділяються щоразу під час виконання порівняння — створіть маску один раз і повторно використовуйте її між операціями замість того, щоб перебудовувати на кожній ітерації.