Data sensor gudang bisa tersimpan sebagai (sensor, waktu, frekuensi), sementara fungsi visualisasi menuntut (frekuensi, sensor, waktu). Untuk pengaturan sumbu yang presisi pada array tiga dimensi ke atas, dua nama menukar posisi sumbu: np.swapaxes dan np.moveaxis. Keduanya terdengar mirip, tetapi semantiknya berbeda dan hasilnya tidak sama.

Bab ini mendemonstrasikan keduanya pada array yang sama, membandingkan pemetaan elemennya, dan membuktikan bahwa keduanya mengembalikan view.

np.swapaxes(a, axis1, axis2) mempertukarkan posisi dua sumbu; sumbu lain tetap di tempatnya. Kedua argumen menerima indeks negatif, sehingga np.swapaxes(data, 0, -1) sah dan berarti menukar sumbu pertama dengan sumbu terakhir — hasilnya sama dengan menukar sumbu 0 dan 2 pada array 3-D.

python
import numpy as np

data = np.arange(24).reshape(2, 3, 4)
hasil = np.swapaxes(data, 0, 2)
print(data.shape, "->", hasil.shape)
print(data[0, 1, 2], hasil[2, 1, 0])

Output yang Dihasilkan:

text
(2, 3, 4) -> (4, 3, 2)
6 6

Baris demi baris:

  1. Baris 3: data (2, 3, 4); anggap 2 wilayah, 3 produk, 4 triwulan.
  2. Baris 4 (np.swapaxes(data, 0, 2)): sumbu 0 dan sumbu 2 dipertukarkan, sehingga bentuk menjadi (4, 3, 2). Sumbu 1 (produk) tidak bergeser.
  3. Baris 5 (uji pemetaan): aturannya hasil[x, y, z] == data[z, y, x]. Elemen data[0, 1, 2] bernilai 6 dan setelah penukaran menempati hasil[2, 1, 0]; keduanya tercetak 6 6.

Memindahkan Sumbu dengan moveaxis #

np.moveaxis(a, source, destination) mengambil satu atau beberapa sumbu, mengeluarkannya dari posisi asal, lalu menyisipkannya di posisi tujuan. Sumbu yang tidak disebut mempertahankan urutan relatifnya.

python
import numpy as np

data = np.arange(24).reshape(2, 3, 4)
hasil = np.moveaxis(data, 0, -1)
print(data.shape, "->", hasil.shape)
print(data[0, 1, 2], hasil[1, 2, 0])

Output yang Dihasilkan:

text
(2, 3, 4) -> (3, 4, 2)
6 6

Penjelasan:

  1. Baris 4 (np.moveaxis(data, 0, -1)): sumbu 0 dikeluarkan dari depan, sumbu 1 dan 2 maju menjaga urutan, lalu sumbu 0 disisipkan di posisi terakhir (-1). Urutan sumbu baru adalah (1, 2, 0), sehingga bentuknya (3, 4, 2).
  2. Baris 5 (uji pemetaan): aturannya hasil[x, y, z] == data[z, x, y]. Elemen data[0, 1, 2] yang sama kini berada di hasil[1, 2, 0]; keduanya bernilai 6.

Baik source maupun destination pada moveaxis juga menerima tuple, sehingga beberapa sumbu bisa dipindahkan sekaligus dengan satu pemanggilan — misalnya np.moveaxis(data, (0, 1), (2, 0)). Untuk array tiga dimensi, satu sumbu saja sudah mencakup kebanyakan kebutuhan nyata.

Hubungan dengan transpose #

Kedua fungsi ini sebenarnya kasus khusus dari transposisi: setiap hasil mereka bisa ditulis ulang sebagai .transpose() dengan tuple axes. Membuktikannya sekaligus menguatkan pemahaman kita tentang tuple axes:

python
import numpy as np

data = np.arange(24).reshape(2, 3, 4)
print(np.array_equal(np.swapaxes(data, 0, 2), data.transpose(2, 1, 0)))
print(np.array_equal(np.moveaxis(data, 0, -1), data.transpose(1, 2, 0)))

Output yang Dihasilkan:

text
True
True

Penjelasan:

  1. Baris 4: menukar sumbu 0 dan 2 setara dengan transpose(2, 1, 0), karena setelah penukaran urutan sumbunya (2, 1, 0); hasilnya tercetak True.
  2. Baris 5: memindahkan sumbu 0 ke belakang setara dengan transpose(1, 2, 0), karena sumbu tersisa (1, 2) maju dan sumbu 0 diletakkan terakhir; hasilnya juga True.

Dengan pemahaman ini kita bebas memilih bentuk penulisan: swapaxes dan moveaxis menyatakan maksud secara eksplisit, sedangkan transpose memberi kendali penuh atas seluruh urutan sumbu. Dalam kode produksi, penulisan yang menyatakan maksud biasanya lebih mudah dirawat, sebab pembaca tidak perlu membayangkan seluruh urutan sumbu hanya untuk memahami satu penukaran.

Perbandingan Semantik dan Sifat View #

Perbedaan keduanya baru terlihat ketika kita membaca hasil dengan indeks yang sama. Kode berikut membandingkan elemen [2, 1, 0] dari kedua hasil, menguji mutasi, dan memeriksa berbagi memori.

python
import numpy as np

data = np.arange(24).reshape(2, 3, 4)
swap = np.swapaxes(data, 0, 2)
move = np.moveaxis(data, 0, -1)
print(swap.shape, move.shape)
print(swap[2, 1, 0], move[2, 1, 0])
swap[0, 0, 0] = 999
print(data[0, 0, 0])
print(np.shares_memory(swap, data), np.shares_memory(move, data))

Output yang Dihasilkan:

text
(4, 3, 2) (3, 4, 2)
6 9
999
True True

Mari kita bedah:

  1. Baris 6 (print(swap.shape, move.shape)): input yang sama menghasilkan dua bentuk berbeda, (4, 3, 2) versus (3, 4, 2). Ini bukti pertama bahwa keduanya bukan operasi yang sama.
  2. Baris 7: pada indeks [2, 1, 0], hasil swap bernilai 6 (menunjuk data[0, 1, 2]), sedangkan hasil move bernilai 9 (menunjuk data[0, 2, 1]). Pemetaan elemennya memang berbeda.
  3. Baris 8-9 (uji mutasi): mengubah swap[0, 0, 0] ikut mengubah data[0, 0, 0] menjadi 999; swap adalah view.
  4. Baris 10 (np.shares_memory): kedua fungsi mengembalikan view yang berbagi buffer dengan data, sehingga keduanya tercetak True.

Tabel berikut merangkum perbandingannya:

Aspeknp.swapaxes(data, 0, 2)np.moveaxis(data, 0, -1)
Aksitukar posisi dua sumbupindahkan sumbu ke posisi tujuan
Bentuk hasil dari (2, 3, 4)(4, 3, 2)(3, 4, 2)
Peta elemenhasil[x, y, z] = data[z, y, x]hasil[x, y, z] = data[z, x, y]
Jenis hasilviewview