Banyak pekerjaan meminta data dalam satu baris: menghitung total seluruh stok, menulis nilai ke CSV, atau membandingkan dua array dengan np.array_equal. Array dua dimensi tidak bisa langsung dipakai untuk keperluan itu, sehingga kita perlu melatakannya (flatten) menjadi array 1-D.
NumPy menyediakan dua cara yang hasil nilainya identik tetapi perilaku memorinya berbeda: flatten() yang selalu menyalin data, dan ravel() yang mengembalikan view bila memungkinkan. Perbedaan ini sering menjadi sumber bug halus, karena hasil ravel() yang diubah akan ikut mengubah array asalnya.
Dua Cara Melatakan Array #
Keduanya membaca elemen baris demi baris dan menghasilkan array 1-D dengan jumlah elemen yang sama.
import numpy as np
stok = np.array([[12, 8, 20], [5, 15, 9]])
flat = stok.flatten()
rata = stok.ravel()
print(flat.shape, rata.shape)
print(flat)
print(np.array_equal(flat, rata))Output yang Dihasilkan:
(6,) (6,)
[12 8 20 5 15 9]
TrueBaris demi baris:
- Baris 3 (
np.array(...)): kita membuat stok berbentuk(2, 3); dua cabang, tiga produk. - Baris 4-5:
flatten()danravel()sama-sama menghasilkan array 1-D berisi enam elemen, sehingga kedua shape tercetak(6,) (6,). - Baris 8 (
np.array_equal): membandingkan isi kedua hasil;Trueberarti nilai elemennya persis sama. Perbedaan keduanya bukan pada isi, melainkan pada relasi memori terhadap array asal.
flatten Menyalin, ravel Berbagi Memori #
Cara paling jelas untuk melihat perbedaannya adalah mengubah hasil masing-masing, lalu mengamati array asal.
import numpy as np
stok = np.array([[12, 8, 20], [5, 15, 9]])
hasil_flatten = stok.flatten()
hasil_ravel = stok.ravel()
hasil_ravel[0] = 999
hasil_flatten[0] = -1
print(stok)
print(hasil_flatten)
print(stok.ravel().base is stok)
print(stok.flatten().base is None)Output yang Dihasilkan:
[[999 8 20]
[ 5 15 9]]
[-1 8 20 5 15 9]
True
TrueMari kita bedah:
- Baris 6 (
hasil_ravel[0] = 999): karenaravel()mengembalikan view, perubahan pada elemen pertama hasil ravel ikut mengubahstok[0, 0]. Baris pertama output menunjukkan999distok. - Baris 7 (
hasil_flatten[0] = -1): karenaflatten()mengembalikan salinan, perubahan ini hanya menyentuhhasil_flatten;stoktetap utuh. Baris kedua output menunjukkan-1hanya di array salinan. - Baris 8 (
stok.ravel().base is stok):.baseview menunjuk ke array pemilik buffer, sehingga tercetakTrue. - Baris 9 (
stok.flatten().base is None): salinan tidak memiliki induk, sehingga.basebernilaiNonedan perbandinganis NonemencetakTrue.
Tabel berikut merangkum kapan kita memilih yang mana:
| Aspek | flatten() | ravel() |
|---|---|---|
| Jenis hasil | selalu salinan baru | view bila memungkinkan |
.base hasil | None | array sumber (saat view) |
| Memori | alokasi baru | berbagi buffer asal |
| Mengubah hasil | tidak memengaruhi asal | memengaruhi asal |
| Tersedia sebagai | method ndarray | method ndarray dan fungsi np.ravel() |
| Cocok untuk | hasil yang akan diubah | hasil yang hanya dibaca |
Bentuk Fungsi np.ravel() #
Selain sebagai method, ravel tersedia sebagai fungsi np.ravel(). Fungsi ini berguna saat array sumber bukan ndarray buatan kita sendiri, misalnya list bersarang dari pustaka lain, karena np.ravel() menerima objek apa pun yang bisa dikonversi menjadi array.
import numpy as np
stok = np.array([[12, 8, 20], [5, 15, 9]])
print(np.ravel(stok))
print(np.shares_memory(np.ravel(stok), stok))Output yang Dihasilkan:
[12 8 20 5 15 9]
TrueBaris pertama membuktikan np.ravel(stok) memberikan hasil yang sama dengan stok.ravel(). Baris kedua mencetak True, yang berarti bentuk fungsi tetap mengembalikan view bila memungkinkan — kebijakan memorinya identik dengan method-nya.
Urutan Pembacaan C dan F #
Parameter order mengatur urutan elemen dibaca saat pelatakan. Nilai "C" (bawaan) membaca baris demi baris, sedangkan "F" membaca kolom demi kolom.
import numpy as np
stok = np.array([[12, 8, 20], [5, 15, 9]])
print(stok.ravel(order="C"))
print(stok.ravel(order="F"))
print(stok.flatten(order="F"))Output yang Dihasilkan:
[12 8 20 5 15 9]
[12 5 8 15 20 9]
[12 5 8 15 20 9]Baris pertama membaca 12, 8, 20 (seluruh baris pertama) sebelum lanjut ke baris kedua. Baris kedua membaca 12, 5 (seluruh kolom pertama) terlebih dahulu, menghasilkan urutan 12, 5, 8, 15, 20, 9. Baris ketiga membuktikan flatten() menerima parameter order yang sama; perbedaan flatten dan ravel memang bukan soal urutan, melainkan soal salinan dan view.
Catatan: np.flat dan flatiter #
Selain flatten() dan ravel(), ndarray punya atribut np.flat. Atribut ini tidak mengembalikan ndarray, melainkan objek flatiter — iterator yang membaca elemen array dalam urutan C. Kita dapat mengiterasinya seperti iterator Python lain, membaca satu elemen lewat indeks, dan mengisi sejumlah posisi sekaligus lewat slice assignment:
import numpy as np
x = np.arange(6).reshape(2, 3)
print(type(x.flat).__name__)
print([int(v) for v in x.flat])
print(x.flat[4])
x.flat[0:3] = 100
print(x)Output yang Dihasilkan:
flatiter
[0, 1, 2, 3, 4, 5]
4
[[100 100 100]
[ 3 4 5]]Baris demi baris:
- Baris 4:
x.flatbertipeflatiter, bukan ndarray — inilah beda utamanya denganravel(). - Baris 5: flatiter dapat diiterasi dan memberi enam elemen dalam urutan C; pembungkus
int()dipakai agar tiap elemen tercetak sebagai angka biasa, bukan repr scalar numpy. - Baris 6: indeks tunggal membaca elemen kelima tanpa melatakan array terlebih dahulu.
- Baris 7: slice assignment mengisi tiga posisi pertama lewat flatiter; penulisan ini menyasar buffer array asal, sehingga
xikut berubah.
Perbandingan singkat: ravel() mengembalikan ndarray (view bila memungkinkan) yang siap dipakai sebagai array — dihitung, di-shape ulang, dioperasikan — sedangkan flatiter hanya untuk membaca dan menulis elemen secara berurutan. Bila hasil akan dipakai sebagai array, gunakan ravel(); bila hanya butuh akses elemen berurutan, x.flat sudah memadai.