W jaki sposób metoda NumPy transpose () permutuje osie tablicy?

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()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?

Frank Hu
źródło
2
0jest pierwszą osią, 1jest drugą, 2jest trzecią itd ... axesParametr do transposezapewnia nową kolejność, w jakiej chcesz je uporządkować, w twoim przykładzie: najpierw druga, potem pierwsza, potem trzecia.
Jaime
Na wyświetlaczu 3D znajdują się bloki, wiersze i kolumny. Twoja transpozycja zmieniła kolejność bloków i wierszy, pozostawiając niezmienione kolumny. To, co było drugim rzędem pierwszego bloku, staje się pierwszym rzędem drugiego bloku.
hpaulj

Odpowiedzi:

190

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ą 2w 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 arrwygląda następująco (z oznaczonymi osiami):

wprowadź opis obrazu tutaj

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:

wprowadź opis obrazu tutaj

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:

wprowadź opis obrazu tutaj

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:

wprowadź opis obrazu tutaj

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 .

Alex Riley
źródło
7

Jak wyjaśniono w dokumentacji :

Domyślnie odwróć wymiary, w przeciwnym razie przesuń osie zgodnie z podanymi wartościami.

Możesz więc przekazać opcjonalny parametr axesdefiniują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)
Falko
źródło
1
cześć dziękuję za odpowiedź. Jednak nadal nie mogę zrozumieć tego problemu, jak widać, kształt ARR to (2,2,4) i arr. Transpozycja (1,0,2) również (2,2,4). to jest tablica trójwymiarowa, jak przekształcić tablicę, gdy przechodzę (1,0,2), czy możesz wyjaśnić, do którego wiersza lub kolumny odnosi się 1,0,2? A jakie są liczby osi w kategoriach numpy?
Frank Hu
1
@FrankHu wizualizuje w przestrzeni 3D, więc obrót osi x, y jest tym, co się tutaj stało. (1,0,2) zostało transponowane z (0,1,2), więc przełączane są pierwsze 2 osie. 0 to numer indeksu osi. Powiedz, x, y, z mapuje do 0,1,2
CodeFarmer
5

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 papieru 0i 8są 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. ¯\_(ツ)_/¯

Robert B.
źródło
Czy mam rację, myśląc, że krotka, której dajesz, 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ś pjako 0, qjako 1, rjako 2 i sjako 3"? Lub widział inny sposób b = a.transpose(axes)środki b.shape == tuple(a.shape[i] for i in axes)?
Tim
Pomysł zamiany osi na grafikę ASCII wyjaśnia moje rozumienie.
Wielkie
0

Wydaje się, że jest to pytanie, a przykład pochodzi z książki Python for Data Analysis autorstwa Wesa McKinneya. Ta funkcja programu transposezostała omówiona w rozdziale 4.1. Transpozycja tablic i zamiana osi .

W przypadku tablic o wyższych wymiarach transposezaakceptuje krotkę numerów osi, aby permutować osie (dla dodatkowego zginania umysłu).

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 wierszy arr[0, 1]i arr[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.

Ayşe Nur
źródło
-3

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)

Raghu Ram
źródło
Nie odpowiedziałeś na pytanie PO, które dzieje się, gdy dokonujesz transpozycji z określonymi osiami .
Robert B
dodano odpowiedź na pytanie, kiedy określone są osie.
Raghu Ram