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.

python
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:

text
(6,) (6,)
[12  8 20  5 15  9]
True

Baris demi baris:

  1. Baris 3 (np.array(...)): kita membuat stok berbentuk (2, 3); dua cabang, tiga produk.
  2. Baris 4-5: flatten() dan ravel() sama-sama menghasilkan array 1-D berisi enam elemen, sehingga kedua shape tercetak (6,) (6,).
  3. Baris 8 (np.array_equal): membandingkan isi kedua hasil; True berarti 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.

python
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:

text
[[999   8  20]
 [  5  15   9]]
[-1  8 20  5 15  9]
True
True

Mari kita bedah:

  1. Baris 6 (hasil_ravel[0] = 999): karena ravel() mengembalikan view, perubahan pada elemen pertama hasil ravel ikut mengubah stok[0, 0]. Baris pertama output menunjukkan 999 di stok.
  2. Baris 7 (hasil_flatten[0] = -1): karena flatten() mengembalikan salinan, perubahan ini hanya menyentuh hasil_flatten; stok tetap utuh. Baris kedua output menunjukkan -1 hanya di array salinan.
  3. Baris 8 (stok.ravel().base is stok): .base view menunjuk ke array pemilik buffer, sehingga tercetak True.
  4. Baris 9 (stok.flatten().base is None): salinan tidak memiliki induk, sehingga .base bernilai None dan perbandingan is None mencetak True.

Tabel berikut merangkum kapan kita memilih yang mana:

Aspekflatten()ravel()
Jenis hasilselalu salinan baruview bila memungkinkan
.base hasilNonearray sumber (saat view)
Memorialokasi baruberbagi buffer asal
Mengubah hasiltidak memengaruhi asalmemengaruhi asal
Tersedia sebagaimethod ndarraymethod ndarray dan fungsi np.ravel()
Cocok untukhasil yang akan diubahhasil 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.

python
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:

text
[12  8 20  5 15  9]
True

Baris 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.

python
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:

text
[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:

python
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:

text
flatiter
[0, 1, 2, 3, 4, 5]
4
[[100 100 100]
 [  3   4   5]]

Baris demi baris:

  1. Baris 4: x.flat bertipe flatiter, bukan ndarray — inilah beda utamanya dengan ravel().
  2. 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.
  3. Baris 6: indeks tunggal membaca elemen kelima tanpa melatakan array terlebih dahulu.
  4. Baris 7: slice assignment mengisi tiga posisi pertama lewat flatiter; penulisan ini menyasar buffer array asal, sehingga x ikut 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.