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()
Co się dzieje, gdy przekażemy do funkcji krotkę liczb całkowitych ?
Mówiąc konkretnie, jest to tablica 3D: w jaki sposób NumPy przekształca tablicę, gdy przekażę krotkę osi (1, 0 ,2)
? Czy możesz wyjaśnić, do którego wiersza lub kolumny odnoszą się te liczby całkowite? A jakie są numery osi w kontekście NumPy?
0
jest pierwszą osią,1
jest drugą,2
jest trzecią itd ...axes
Parametr dotranspose
zapewnia nową kolejność, w jakiej chcesz je uporządkować, w twoim przykładzie: najpierw druga, potem pierwsza, potem trzecia.Odpowiedzi:
Aby przetransponować tablicę, NumPy po prostu zamienia informacje o kształcie i kroku dla każdej osi. Oto kroki:
>>> arr.strides (64, 32, 8) >>> arr.transpose(1, 0, 2).strides (32, 64, 8)
Zauważ, że operacja transpozycji zamieniła kroki dla osi 0 i osi 1. Długości tych osi również zostały zamienione (obie długości są
2
w tym przykładzie).Aby to się stało, nie trzeba kopiować żadnych danych; NumPy może po prostu zmienić wygląd podstawowej pamięci, aby skonstruować nową tablicę.
Wizualizacja kroków
Wartość kroku reprezentuje liczbę bajtów, które muszą zostać pokonane w pamięci, aby osiągnąć następną wartość osi tablicy.
Teraz nasza tablica 3D
arr
wygląda następująco (z oznaczonymi osiami):Ta tablica jest przechowywana w ciągłym bloku pamięci ; zasadniczo jest jednowymiarowy. Aby zinterpretować to jako obiekt 3D, NumPy musi przeskoczyć pewną stałą liczbę bajtów, aby poruszać się wzdłuż jednej z trzech osi:
Ponieważ każda liczba całkowita zajmuje 8 bajtów pamięci (używamy int64 dtype), wartość kroku dla każdego wymiaru jest 8-krotnością liczby wartości, które musimy przeskoczyć. Na przykład, aby poruszać się wzdłuż osi 1, przeskakuje się cztery wartości (32 bajty), a aby przejść wzdłuż osi 0, należy przeskoczyć osiem wartości (64 bajty).
Kiedy piszemy
arr.transpose(1, 0, 2)
, zamieniamy się osiami 0 i 1. Transponowana tablica wygląda następująco:Wszystko, co musi zrobić NumPy, to zamienić informacje o kroku dla osi 0 i osi 1 (oś 2 pozostaje niezmieniona). Teraz musimy przeskoczyć dalej, aby przejść wzdłuż osi 1 niż osi 0:
Ta podstawowa koncepcja działa dla dowolnej permutacji osi tablicy. Rzeczywisty kod, który obsługuje transpozycję, jest napisany w C i można go znaleźć tutaj .
źródło
Jak wyjaśniono w dokumentacji :
Możesz więc przekazać opcjonalny parametr
axes
definiujący nową kolejność wymiarów.Np. Transpozycja dwóch pierwszych wymiarów tablicy pikseli RGB VGA:
>>> x = np.ones((480, 640, 3)) >>> np.transpose(x, (1, 0, 2)).shape (640, 480, 3)
źródło
W notacji C tablica wyglądałaby następująco:
int arr[2][2][4]
który jest tablicą 3D zawierającą 2 tablice 2D. Każda z tych tablic 2D ma macierz 2 1D, każda z tych tablic 1D ma 4 elementy.
Więc masz trzy wymiary. Osie to 0, 1, 2, o rozmiarach 2, 2, 4. Dokładnie tak numpy traktuje osie tablicy N-wymiarowej.
Więc
arr.transpose((1, 0, 2))
weźmy oś 1 i umieścimy ją w pozycji 0, osi 0 i umieścimy ją w pozycji 1, a oś 2 i pozostawimy w pozycji 2. Skutecznie permutujesz osie:0 -\/-> 0 1 -/\-> 1 2 ----> 2
Innymi słowy
1 -> 0, 0 -> 1, 2 -> 2
. Osie docelowe są zawsze w porządku, więc wystarczy określić osie źródłowe. Odczytać krotki w tej kolejności:(1, 0, 2)
.W tym przypadku nowe wymiary tablicy są ponownie
[2][2][4]
, tylko dlatego, że osie 0 i 1 miały ten sam rozmiar (2).Bardziej interesująca jest transpozycja,
(2, 1, 0)
która daje tablicę[4][2][2]
.0 -\ /--> 0 1 --X---> 1 2 -/ \--> 2
Innymi słowy
2 -> 0, 1 -> 1, 0 -> 2
. Odczytać krotki w tej kolejności:(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]]])
Skończyło się na
int[4][2][2]
.Prawdopodobnie lepiej zrozumiesz, jeśli wszystkie wymiary mają różne rozmiary, abyś mógł zobaczyć, gdzie poszła każda oś.
Dlaczego jest pierwszym elementem wewnętrznym
[0, 8]
? Ponieważ jeśli wizualizujesz swoją tablicę 3D jako dwa arkusze papieru0
i8
są one ustawione w jednej linii, jeden na jednym papierze, a drugi na drugim, oba w lewym górnym rogu. Transponując(2, 1, 0)
, mówisz, że chcesz, aby kierunek papieru na papierze przebiegał teraz wzdłuż arkusza od lewej do prawej, a kierunek od lewej do prawej, aby teraz przechodził od papieru do papieru. Miałeś 4 elementy przechodzące od lewej do prawej, więc teraz masz zamiast tego cztery kartki papieru. Miałeś 2 dokumenty, więc teraz masz 2 elementy przechodzące od lewej do prawej.Przepraszam za okropną grafikę ASCII.
¯\_(ツ)_/¯
źródło
transpose()
nie jest matematyczną permutacją ani niczym? To dosłownie tylko instrukcja mówiąca „ustaw osie w tych pozycjach”? Np..transpose(p, q, r, s)
Mówisz "umieść ośp
jako 0,q
jako 1,r
jako 2 is
jako 3"? Lub widział inny sposóbb = a.transpose(axes)
środkib.shape == tuple(a.shape[i] for i in axes)
?Wydaje się, że jest to pytanie, a przykład pochodzi z książki Python for Data Analysis autorstwa Wesa McKinneya. Ta funkcja programu
transpose
została omówiona w rozdziale 4.1. Transpozycja tablic i zamiana osi .Tutaj „permute” oznacza „przegrupowanie”, czyli przestawienie kolejności osi.
Liczby w
.transpose(1, 0, 2)
określają sposób zmiany kolejności osi w porównaniu z oryginałem. Używając.transpose(1, 0, 2)
, mamy na myśli „Zmień pierwszą siekierę na drugą”. Jeśli użyjemy.transpose(0, 1, 2)
, tablica pozostanie taka sama, ponieważ nie ma nic do zmiany; jest to kolejność domyślna.Przykład w książce z
(2, 2, 4)
tablicą rozmiarów nie jest zbyt jasny, ponieważ pierwsza i druga oś mają ten sam rozmiar. Więc wynik końcowy nie wydaje się zmieniać, z wyjątkiem zmiany kolejności wierszyarr[0, 1]
iarr[1, 0]
.Jeśli spróbujemy innego przykładu z trójwymiarową tablicą, w której każdy wymiar ma inny rozmiar, część przegrupowania stanie się bardziej przejrzysta.
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]]])
Tutaj są oryginalne rozmiary tablic
(2, 3, 4)
. Zmieniliśmy 1 i 2 miejsce, więc staje się(3, 2, 4)
rozmiar. Jeśli przyjrzymy się bliżej, aby zobaczyć, jak dokładnie doszło do przegrupowania; wydaje się, że tablice liczb zmieniły się według określonego wzorca. Używając papierowej analogii @ RobertB , gdybyśmy wzięli 2 fragmenty liczb i zapisali każdy z nich na arkuszach, a następnie wzięliby jeden wiersz z każdego arkusza, aby skonstruować jeden wymiar tablicy, mielibyśmy teraz tablicę o wymiarach 3x2x4 , licząc od najbardziej zewnętrznej do najbardziej wewnętrznej warstwy.[ 0, 1, 2, 3] \ [12, 13, 14, 15]
[ 4, 5, 6, 7] \ [16, 17, 18, 19]
[ 8, 9, 10, 11] \ [20, 21, 22, 23]
Dobrym pomysłem może być zabawa z tablicami o różnych rozmiarach i zmiana różnych osi, aby uzyskać lepszą intuicję, jak to działa.
źródło
Podsumowując 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.
kiedy jest przekazywany parametr krotki, osie są permutowane zgodnie z krotką. Na przykład
a = np.array (range (24), int) .reshape ((2,3,4))
a [i, j, k] równa się a.transpose ((2,0,1)) [k, i, j]
oś 0 zajmuje 2 miejsce
oś 1 zajmuje 3 miejsce
oś 2 opowieści 1. miejsce
oczywiście musimy uważać, aby wartości w parametrze krotki przekazane do transpozycji były unikalne i mieściły się w zakresie (liczba osi)
źródło