У цьому посібнику ви ознайомитеся з тим, як застосовувати функцію NumPy `reshape()` для трансформації структури масивів NumPy, зберігаючи при цьому їхні вихідні значення.
Під час оперування масивами NumPy, нерідко виникає потреба у зміні їхньої форми, перетворюючи існуючий масив на інший з іншими вимірами. Це може бути особливо корисним у процесі обробки даних, коли потрібно виконати декілька етапів перетворення.
Функція NumPy `reshape()` робить цей процес простим і зручним. Протягом цього посібника ви освоїте синтаксис використання `reshape()`, а також навчитеся трансформувати масиви у різноманітні розмірності.
Що являє собою зміна форми масивів NumPy?
При роботі з масивами NumPy, часто починають зі створення одновимірного масиву чисел, який потім можна перетворити на масив потрібної форми.
Це особливо цінно, коли розмірність нового масиву невідома на початку або визначається динамічно під час виконання коду. Також, окремі етапи обробки даних можуть вимагати, щоб вхідні дані мали певну специфічну форму.
Саме в таких випадках на допомогу приходить зміна форми масивів.
Розглянемо, наприклад, вектор – одновимірний масив з 6 елементів. Його можна перетворити на масиви з формами 2×3, 3×2, 6×1 та іншими.
▶️ Для виконання прикладів з цього посібника, вам знадобиться Python і NumPy. Якщо ви ще не встановили NumPy, скористайтеся нашою інструкцією зі встановлення NumPy.
Тепер, ви можете імпортувати NumPy під псевдонімом `np`, використовуючи команду: `import numpy as np`.
Далі розглянемо синтаксис `reshape()`.
Синтаксис функції NumPy `reshape()`
Синтаксис використання функції NumPy `reshape()` виглядає наступним чином:
np.reshape(arr, newshape, order="C"|'F'|'A')
- `arr` – це будь-який коректний об’єкт масиву NumPy, тобто масив, який потрібно трансформувати.
- `newshape` – це форма нового масиву. Вона може бути задана як ціле число або як кортеж.
- Якщо `newshape` – ціле число, тоді повернений масив буде одновимірним.
- `order` – це порядок, в якому будуть зчитуватися елементи масиву, що трансформується.
- За замовчуванням встановлено значення ‘C’, що означає, що елементи вихідного масиву будуть зчитуватися в порядку, подібному до індексації в C (починаючи з 0).
- ‘F’ позначає індексацію, подібну до Fortran (починаючи з 1). А ‘A’ зчитує елементи в C-подібному або Fortran-подібному порядку, залежно від розміщення в пам’яті масиву `arr`.
Що ж повертає функція `np.reshape()`?
Вона повертає змінене представлення початкового масиву, якщо це можливо. В іншому випадку повертається копія масиву.
Вище ми зазначили, що NumPy `reshape()` намагатиметься повернути представлення, коли це можливо. В іншому випадку, вона поверне копію. Далі розглянемо різницю між представленням та копією.
Представлення чи копія масивів NumPy
Як випливає з назви, копія – це дублікат вихідного масиву. Будь-які зміни, внесені в копію, не вплинуть на оригінальний масив.
З іншого боку, представлення – це змінений вид оригінального масиву. Це означає, що будь-які зміни, внесені в представлення, також вплинуть на вихідний масив, і навпаки.
Застосування NumPy `reshape()` для трансформації 1D-масиву в 2D-масив
#1. Почнемо зі створення прикладу масиву, використовуючи функцію `np.arange()`.
Нам потрібен масив із 12 чисел, від 1 до 12, який ми назвемо `arr1`. Оскільки функція NumPy `arange()` за замовчуванням виключає кінцеву точку, ми встановимо значення зупинки на 13.
Тепер, використовуючи описаний вище синтаксис, ми змінимо форму `arr1` з 12 елементів у двовимірний масив форми (4,3). Назвемо його `arr2` з 4 рядками та 3 стовпцями.
import numpy as np arr1 = np.arange(1,13) print("Оригінальний масив, до зміни форми:\n") print(arr1) # Зміна форми масиву arr2 = np.reshape(arr1,(4,3)) print("\nЗмінений масив:") print(arr2)
Переглянемо оригінальні та змінені масиви.
Оригінальний масив, до зміни форми: [ 1 2 3 4 5 6 7 8 9 10 11 12] Змінений масив: [[ 1 2 3] [ 4 5 6] [ 7 8 9] [10 11 12]]
Замість того, щоб передавати масив як аргумент функції `np.reshape()`, ви також можете викликати метод `.reshape()` для оригінального масиву.
Ви можете запустити `dir(arr1)`, і він виведе список всіх можливих методів і атрибутів, які ви можете використовувати для об’єкта масиву `arr1`.
dir(arr1) # Вивід [ ... ... 'reshape' ... .. ]
В вищенаведеному коді можна побачити, що `.reshape()` є дійсним методом для використання в існуючому масиві NumPy `arr1`.
▶️ Отже, ви також можете використовувати наступний спрощений синтаксис для зміни форми масивів NumPy:
arr.reshape(d0,d1,...,dn) # де: # d0, d1,..,dn - це виміри зміненого масиву # d0 * d1 * ...* dn = N, кількість елементів в arr
В подальшому, в наших прикладах, будемо використовувати цей синтаксис.
#2. Спробуємо змінити форму нашого 12-елементного вектора в масив 12 x 1.
import numpy as np arr1 = np.arange(1,13) print("Оригінальний масив, до зміни форми:\n") print(arr1) # Зміна форми масиву arr3 = arr1.reshape(12,1) print("\nЗмінений масив:") print(arr3)
У виводі нижче видно, що форма масиву змінена згідно з запитом.
Оригінальний масив, до зміни форми: [ 1 2 3 4 5 6 7 8 9 10 11 12] Змінений масив: [[ 1] [ 2] [ 3] [ 4] [ 5] [ 6] [ 7] [ 8] [ 9] [10] [11] [12]]
❔ Як нам перевірити, отримали ми копію чи представлення?
Щоб це перевірити, можна викликати атрибут `base` для отриманого масиву.
- Якщо масив є копією, атрибут `base` буде дорівнювати `None`.
- Якщо масив є представленням, атрибут `base` буде повертати вихідний масив.
Давайте це швидко перевіримо.
arr3.base # Вивід array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
Як бачите, атрибут `base` для `arr3` повертає початковий масив. Це означає, що ми отримали представлення вихідного масиву.
#3. Спробуємо трансформувати вектор в інший двовимірний масив 2 x 6.
import numpy as np arr1 = np.arange(1,13) print("Оригінальний масив, до зміни форми:\n") print(arr1) # Зміна форми масиву arr4 = arr1.reshape(2,6) print("\nЗмінений масив:") print(arr4)
Ось результат:
Оригінальний масив, до зміни форми: [ 1 2 3 4 5 6 7 8 9 10 11 12] Змінений масив: [[ 1 2 3 4 5 6] [ 7 8 9 10 11 12]]
В наступному розділі ми трансформуємо `arr1` в тривимірний масив.
Застосування NumPy `reshape()` для трансформації 1D-масиву в 3D-масив
Щоб трансформувати `arr1` в тривимірний масив, задамо потрібні розміри (1, 4, 3).
import numpy as np arr1 = np.arange(1,13) print("Оригінальний масив, до зміни форми:\n") print(arr1) # Зміна форми масиву arr3D = arr1.reshape(1,4,3) print("\nЗмінений масив:") print(arr3D)
Тепер ми створили 3D-масив з тими ж 12 елементами, що й в оригінальному масиві `arr1`.
Оригінальний масив, до зміни форми: [ 1 2 3 4 5 6 7 8 9 10 11 12] Змінений масив: [[[ 1 2 3] [ 4 5 6] [ 7 8 9] [10 11 12]]]
Як діагностувати помилки значень при зміні форми масиву
Як ви пам’ятаєте з синтаксису, зміна форми буде успішною лише тоді, коли добуток розмірів дорівнює кількості елементів у вихідному масиві.
import numpy as np arr1 = np.arange(1,13) print("Оригінальний масив, до зміни форми:\n") print(arr1) # Зміна форми масиву arr2D = arr1.reshape(4,4) print("\nЗмінений масив:") print(arr2D)
У даному прикладі ми намагаємося змінити форму масиву з 12 елементів у масив 4×4 з 16 елементами. Інтерпретатор поверне помилку значення, як показано нижче.
Оригінальний масив, до зміни форми: [ 1 2 3 4 5 6 7 8 9 10 11 12] ----------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-11-63552bcc8c37> in <module>() 6 7 # Зміна форми масиву ----> 8 arr2 = arr1.reshape(4,4) 9 print("\nЗмінений масив:") 10 print(arr2) ValueError: cannot reshape array of size 12 into shape (4,4)
Щоб уникнути таких помилок, можна використовувати значення -1 для автоматичного визначення форми одного з вимірів, базуючись на загальній кількості елементів.
Наприклад, якщо ви знаєте n-1 вимірів, то ви можете використовувати -1, щоб визначити n-й вимір у зміненому масиві.
Припустимо, що у вас є масив з 24 елементами і вам потрібно змінити його форму на тривимірний масив. Припустимо, що вам потрібно 3 рядки та 4 стовпці. В такому випадку, ви можете передати значення -1 вздовж третього виміру.
import numpy as np arr1 = np.arange(1,25) print("Оригінальний масив, до зміни форми:\n") print(arr1) # Зміна форми масиву arr_res = arr1.reshape(4,3,-1) print("\nЗмінений масив:") print(arr_res) print(f"Форма arr_res:{arr_res.shape}")
Якщо перевірити форму масиву, то ви побачите, що змінений масив має розмір 2 вздовж третього виміру.
Оригінальний масив, до зміни форми: [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24] Змінений масив: [[[ 1 2] [ 3 4] [ 5 6]] [[ 7 8] [ 9 10] [11 12]] [[13 14] [15 16] [17 18]] [[19 20] [21 22] [23 24]]] Форма arr_res:(4, 3, 2)
Це особливо зручно для зведення масиву, про що ви дізнаєтесь далі.
Застосування NumPy `reshape()` для зведення масиву
Іноді виникає потреба повернутися від N-вимірного масиву до зведеного масиву. Наприклад, ви можете захотіти звести зображення до довгого вектора пікселів.
Розглянемо простий приклад виконання наступних дій:
- Створимо масив зображення в градаціях сірого розміром 3×3, `img_arr`, з пікселями в діапазоні від 0 до 255.
- Потім зведемо цей `img_arr` та виведемо зведений масив `flat_arr`.
- Також виведемо форми `img_arr` та `flat_arr` для перевірки.
img_arr = np.random.randint(0, 255, (3,3)) print(img_arr) print(f"Форма img_arr: {img_arr.shape}") flat_arr = img_arr.reshape(-1) print(flat_arr) print(f"Форма flat_arr: {flat_arr.shape}")
Ось результат:
[[195 145 77] [ 63 193 223] [215 43 36]] Форма img_arr: (3, 3) [195 145 77 63 193 223 215 43 36] Форма flat_arr: (9,)
У наведеному вище коді видно, що `flat_arr` – це одновимірний вектор значень пікселів з 9 елементами.
Підсумки 👩🏫
Настав час коротко підсумувати вивчене.
- Використовуйте `np.reshape(arr, newshape)` для зміни форми масиву `arr` на форму, задану в `newshape`. `newshape` є кортежем, який визначає розміри зміненого масиву.
- Крім того, використовуйте `arr.reshape(d0, d1, …, dn)` для зміни форми `arr` так, щоб він мав форму `d0 x d1 x … x dn`.
- Перевірте, чи виконується умова `d0 * d1 * … * dn = N`, де `N` – кількість елементів у вихідному масиві, щоб уникнути помилок значень під час зміни форми.
- Використовуйте значення -1 максимум для одного з розмірів у новій формі, якщо ви хочете, щоб цей розмір був визначений автоматично.
- Нарешті, ви можете використовувати `arr.reshape(-1)` для зведення масиву.
Тепер, коли ви знаєте, як використовувати NumPy `reshape()`, дізнайтеся, як працює функція NumPy `linspace()`.
Ви можете спробувати приклади коду в блокноті Jupyter, якщо вам це зручно. Якщо ви шукаєте інші середовища розробки, перегляньте наш посібник про альтернативи Jupyter.