Как метод transpose() NumPy переставляет оси массива?
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]]])
когда мы передаем кортеж целых чисел в
5 ответов
чтобы транспонировать массив, NumPy просто меняет форму и информацию шага для каждой оси. Вот шаги:
>>> arr.strides
(64, 32, 8)
>>> arr.transpose(1, 0, 2).strides
(32, 64, 8)
обратите внимание, что операция транспонирования поменяла шаги для оси 0 и оси 1. Длины этих осей также были заменены (обе длины 2
в этом примере).
для этого не нужно копировать данные; NumPy может просто изменить, как он смотрит на базовую память для создания нового матрица.
визуализация успехов
значение stride представляет количество байтов,которые должны быть перемещены в памяти для достижения следующего значения оси массива.
теперь, наш 3D массив arr
выглядит это (с маркировкой осей):
этот массив хранится в непрерывный блок памяти; по существу, он одномерен. Чтобы интерпретировать его как 3D-объект, NumPy необходимо перепрыгнуть через определенное постоянное количество байтов, чтобы двигаться по одной из трех осей:
поскольку каждое целое число занимает 8 байт памяти (мы используем int64 dtype), значение шага для каждого измерения в 8 раз больше количества значений, которые нам нужно перейти. Например, для перемещения вдоль оси 1 необходимо перейти к четырем значениям (32 байта), а для перемещения вдоль оси 0-к восьми значениям (64 байта).
когда мы пишем arr.transpose(1, 0, 2)
мы меняем оси 0 и 1. Транспонированный массив выглядит следующим образом:
все, что NumPy нужно сделать, это поменять информацию о шаге для оси 0 и оси 1 (ось 2 не изменилась). Теперь мы должны прыгать дальше двигаться вдоль оси 1, чем ось 0:
эта основная концепция работает для любой перестановки осей массива. Фактический код, который обрабатывает транспонирование, написан на C и может быть найденным здесь.
Как пояснил документации:
по умолчанию измените размеры, в противном случае переставьте оси в соответствии с заданными значениями.
таким образом, вы можете передать необязательный параметр axes
определение нового порядка измерений.
например. транспонирование первых двух измерений массива пикселей RGB VGA:
>>> x = np.ones((480, 640, 3))
>>> np.transpose(x, (1, 0, 2)).shape
(640, 480, 3)
в нотации C Ваш массив будет:
int arr[2][2][4]
который представляет собой 3D-массив, имеющий 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]
? Потому что, если вы визуализируете свой 3D-массив в виде двух листов бумаги,0
и 8
выстроились в ряд, один на одной бумаге и один на другой бумаге, обе в левом верхнем углу. Путем транспонирования (2, 1, 0)
вы говорите, что хотите, чтобы направление от бумаги к бумаге теперь маршировать по бумаге слева направо, а направление слева направо теперь перейти от бумаги к бумаге. У вас было 4 элемента, идущих слева направо, поэтому теперь у вас есть четыре листа бумаги. И у вас было 2 статьи, так что теперь у вас есть 2 элемента, идущих слева направо.
извините за ужасное искусство ASCII. ¯\_(ツ)_/¯
.перекроить(num1,пит2,клавиша num3).... три числа соотносятся с num1 = 0, num2 = 1 и num3 = 2. Таким образом, при транспонировании наличие (2,0,1) означает переключение вокруг исходного порядка num1,num2 и num3.
.reshape works like .reshape(5,5,2)
^ ^ ^
| | |
I want 5,5x2's
ex.
переменная.перекроить(5,5,2)
...
...
.транспонировать(2,0,1) / / действительно означает переделывать reshape(2,5,5)...то есть я хочу матрицы 2, 5x5
-вся документация в мире не могла сделать это ясно, пока я не протестировал его с:
import numpy as np
arr = np.arange(50).reshape(5,5,2)
print(arr)
arr3d = arr.transpose(2,0,1)
print(arr3d)
-С тем не менее, используя мою теорию, я не знаю, почему.транспонирование (1,0,2) не дает выхода, который выглядит так же, как оригинал, переключение 5 с 5 ничего не должно делать, но это делает следующее:
[[[ 0 1]
[10 11]
[20 21]
[30 31]
[40 41]]
[[ 2 3]
[12 13]
[22 23]
[32 33]
[42 43]]
[[ 4 5]
[14 15]
[24 25]
[34 35]
[44 45]]
[[ 6 7]
[16 17]
[26 27]
[36 37]
[46 47]]
[[ 8 9]
[18 19]
[28 29]
[38 39]
[48 49]]]
- мой intsructor на udemy не мог понять, почему и как (1,0,2) сделать это.
подводя итоги 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.массив (диапазон (24), int).изменить форму ((2,3,4))
a [i,j,k] равно a.транспонировать ((2,0,1)) [k,i,j]
оси 0 занимает 2-е место
оси 1 занимает 3-е место
ось 2 сказки 1-е место
конечно, нам нужно позаботиться о том, чтобы значения в параметр кортежа, передаваемый для транспонирования, уникален и находится в диапазоне (количество осей)