Як метод транспонування () NumPy переставляє осі масиву?


81
In [28]: arr = np.arange(16).reshape((2, 2, 4))

In [29]: arr
Out[29]: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])


In [32]: arr.transpose((1, 0, 2))
Out[32]: 
array([[[ 0,  1,  2,  3],
        [ 8,  9, 10, 11]],

       [[ 4,  5,  6,  7],
        [12, 13, 14, 15]]])

Що відбувається, коли ми передаємо функцію кортеж цілих чисел transpose()?

Точніше, це тривимірний масив: як NumPy перетворює масив, коли я передаю кортеж осей (1, 0 ,2)? Чи можете ви пояснити, до якого рядка чи стовпця посилаються ці цілі числа? А що таке числа осей у контексті NumPy?



2
0це перша вісь, 1друга, 2третя і т.д. ... axesПараметр, що transposeзабезпечує новий порядок, за яким ви хочете, щоб вони були розташовані, у вашому прикладі: спочатку друга, потім перша, потім третя.
Хайме,

На 3d-дисплеї є блоки, рядки та стовпці. Транспонування змінило порядок блоків і рядків, залишивши стовпці незмінними. Те, що раніше було 2-го ряду 1-го блоку, стає 1-м рядком 2-го блоку.
hpaulj

Відповіді:


190

Щоб транспонувати масив, NumPy просто поміняє місцями інформацію про форму та крок для кожної осі. Ось кроки:

>>> arr.strides
(64, 32, 8)

>>> arr.transpose(1, 0, 2).strides
(32, 64, 8)

Зверніть увагу, що операція транспонування поміняла кроки на осі 0 та осі 1. Довжини цих осей також поміняли місцями (обидві довжини наведені 2в цьому прикладі).

Для цього не потрібно копіювати дані; NumPy може просто змінити вигляд основної пам'яті для побудови нового масиву.


Візуалізація кроків

Значення кроку представляє кількість байтів, які потрібно пройти в пам’яті, щоб досягти наступного значення осі масиву.

Тепер наш 3D-масив arrвиглядає так (з позначеними осями):

введіть тут опис зображення

Цей масив зберігається у суміжному блоці пам'яті ; по суті він одновимірний. Щоб інтерпретувати його як тривимірний об'єкт, NumPy повинен перестрибнути певну постійну кількість байтів, щоб рухатися вздовж однієї з трьох осей:

введіть тут опис зображення

Оскільки кожне ціле число займає 8 байт пам'яті (ми використовуємо тип int64 d), значення кроку для кожного виміру в 8 разів перевищує кількість значень, які нам потрібно перейти. Наприклад, для переміщення вздовж осі 1 перескакуються чотири значення (32 байта), а для переміщення вздовж осі 0 потрібно перевести вісім значень (64 байта).

Коли ми пишемо, arr.transpose(1, 0, 2)ми міняємо місцями осі 0 і 1. Транспонований масив виглядає так:

введіть тут опис зображення

Все, що потрібно зробити NumPy, - це поміняти інформацію про крок на вісь 0 та вісь 1 (вісь 2 незмінна). Тепер ми повинні стрибнути далі, щоб рухатися вздовж осі 1, ніж осі 0:

введіть тут опис зображення

Ця основна концепція працює для будь-якої перестановки осей масиву. Фактичний код, який обробляє транспонування, написаний на C і його можна знайти тут .


7

Як пояснюється в документації :

За замовчуванням змініть розміри у зворотному напрямку, інакше переставте осі відповідно до заданих значень.

Таким чином, ви можете передати необов’язковий параметр, що axesвизначає новий порядок розмірів.

Наприклад, транспонування перших двох вимірів піксельної масиву RGB VGA:

 >>> x = np.ones((480, 640, 3))
 >>> np.transpose(x, (1, 0, 2)).shape
 (640, 480, 3)

1
привіт, дякую за вашу відповідь. Однак я все ще не можу зрозуміти цю проблему, як ви бачите, форма arr має (2,2,4), а arr.transpose (1,0,2) - (2,2,4) теж. це тривимірний масив, як перетворити масив, коли я передаю (1,0,2), чи можете ви пояснити, до якого рядка або стовпця відноситься 1,0,2? А що таке числа осей з точки зору numpy?
Frank Hu

1
@FrankHu візуалізує в тривимірному просторі, тож тут відбулося обертання осі x, y. (1,0,2) було перенесено з (0,1,2), отже, перша 2 вісь перемикається. 0 - індексний номер осі. Скажімо, x, y, z відображає на 0,1,2
CodeFarmer

5

У нотації C ваш масив буде таким:

int arr[2][2][4]

це тривимірний масив, що має 2 2D масиви. Кожен з цих 2D-масивів має 2 1D-масиви, кожен з цих 1D-масивів має 4 елементи.

Отже, у вас є три виміри. Осі дорівнюють 0, 1, 2, з розмірами 2, 2, 4. Це саме те, як numpy обробляє осі N-мірного масиву.

Отже, arr.transpose((1, 0, 2))візьмемо вісь 1 і помістимо її в положення 0, вісь 0 і поставимо в положення 1, а вісь 2 і залишимо в положенні 2. Ви ефективно переставляєте осі:

0 -\/-> 0
1 -/\-> 1
2 ----> 2

Іншими словами, 1 -> 0, 0 -> 1, 2 -> 2. Осі призначення завжди в порядку, тому все, що вам потрібно, це вказати вихідні осі. Вважайте кортеж в такому порядку: (1, 0, 2).

У цьому випадку ваші нові розміри масиву знову [2][2][4], лише тому, що осі 0 і 1 мали однаковий розмір (2).

Більш цікавим є транспонування, (2, 1, 0)що дає вам масив [4][2][2].

0 -\ /--> 0
1 --X---> 1
2 -/ \--> 2

Іншими словами, 2 -> 0, 1 -> 1, 0 -> 2. Вважайте кортеж в такому порядку: (2, 1, 0).

>>> arr.transpose((2,1,0))
array([[[ 0,  8],
        [ 4, 12]],

       [[ 1,  9],
        [ 5, 13]],

       [[ 2, 10],
        [ 6, 14]],

       [[ 3, 11],
        [ 7, 15]]])

Ви закінчили з int[4][2][2].

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

Чому перший внутрішній елемент [0, 8]? Тому що якщо ви візуалізуєте свій тривимірний масив як два аркуші паперу 0і 8вишикувались один на один, а інший на іншому, обидва вгорі ліворуч. Транспонуючи, (2, 1, 0)ви говорите, що хочете, щоб напрямок папір-папір тепер рухався уздовж паперу зліва направо, а напрямок зліва направо - тепер переходило з паперу на папір. У вас було 4 елементи, які рухались зліва направо, тож тепер у вас є чотири аркуші паперу. І у вас було 2 документи, тож тепер у вас є 2 елементи, які рухаються зліва направо.

Вибачте за жахливе мистецтво ASCII. ¯\_(ツ)_/¯


Чи правильно я вважаю, що кортеж, який ви надаєте transpose(), не є математичною перестановкою чи чимось іншим? Це буквально просто інструкції, що говорять "змусити осі зараз бути в таких положеннях"? Наприклад, .transpose(p, q, r, s)ви кажете "поставити вісь pяк 0-ту, qяк 1-ю, rяк 2-ю і sяк 3-ю"? Або бачили інший спосіб b = a.transpose(axes)означає b.shape == tuple(a.shape[i] for i in axes)?
Тім

Ідея обміну віссю з мистецтвом ASCII уточнює моє розуміння. Велике спасибі
K_inverse

0

Здається, питання та приклад беруть початок із книги « Пітон для аналізу даних» Веса МакКінні. Ця особливість transposeзгадується в розділі 4.1. Транспонування масивів та обмін сокирами .

Для масивів вищих розмірів transposeбуде прийнято набір номерів осей для перестановки осей (для додаткового вигину розуму).

Тут "перестановка" означає "переставляти", таким чином переставляючи порядок осей.

Цифри в .transpose(1, 0, 2)визначають, як змінюється порядок осей порівняно з оригіналом. Використовуючи .transpose(1, 0, 2), ми маємо на увазі: "Змінити 1-ю сокиру на 2-ю". Якщо ми використаємо .transpose(0, 1, 2), масив залишиться незмінним, тому що нічого змінити немає; це замовлення за замовчуванням.

Приклад у книзі з (2, 2, 4)розмірним масивом не дуже зрозумілий, оскільки 1-я та 2-а осі мають однакові розміри. Отже, кінцевий результат, здається, не змінюється, окрім переупорядкування рядків arr[0, 1]та arr[1, 0].

Якщо ми спробуємо інший приклад із тривимірним масивом, причому кожен вимір має різний розмір, частина перестановки стає більш зрозумілою.

In [2]: x = np.arange(24).reshape(2, 3, 4)

In [3]: x
Out[3]: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[12, 13, 14, 15],
        [16, 17, 18, 19],
        [20, 21, 22, 23]]])

In [4]: x.transpose(1, 0, 2)
Out[4]: 
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])

Тут оригінальні розміри масиву (2, 3, 4). Ми змінили 1-го та 2-го, тож він стає (3, 2, 4)в розмірі. Якщо ми придивимося ближче, щоб побачити, як саме відбулася перебудова; масиви чисел, здається, змінилися за певним зразком. Використовуючи аналогію з папером @ RobertB , якби ми взяли 2 шматки чисел і записали кожен на аркушах, а потім взяли по одному рядку з кожного аркуша, щоб побудувати один вимір масиву, ми б тепер мали масив розміром 3x2x4 , вважаючи від зовнішнього до самого внутрішнього шару.

[ 0,  1,  2,  3] \ [12, 13, 14, 15]

[ 4,  5,  6,  7] \ [16, 17, 18, 19]

[ 8,  9, 10, 11] \ [20, 21, 22, 23]

Це може бути гарною ідеєю грати з масивами різного розміру та міняти різні осі, щоб краще зрозуміти, як це працює.


-3

Підсумовуючи a.transpose () [i, j, k] = a [k, j, i]

a = np.array( range(24), int).reshape((2,3,4))
a.shape gives (2,3,4)
a.transpose().shape gives (4,3,2)  shape tuple is reversed.

коли передано параметр кортежу, осі переставляються відповідно до кортежу. Наприклад

a = np.array (діапазон (24), int) .reshape ((2,3,4))

a [i, j, k] дорівнює a.transpose ((2,0,1)) [k, i, j]

вісь 0 займає 2 місце

вісь 1 займає 3 місце

вісь 2 казки 1 місце

звичайно, нам потрібно подбати про те, щоб значення параметра кортежу, передані для транспонування, були унікальними та в діапазоні (кількість осі)


Ви не зверталися до запитання OP, що відбувається під час транспонування за вказаними осями .
Роберт Б,

додана відповідь на запитання, коли вказані осі.
Рагху Рам,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.