Topik ini membahas dua cara mengubah array menjadi satu dimensi, yaitu metode ravel() dan flatten(). Hasil keduanya tampak sama, tetapi keduanya berbeda dalam hal memori, karena ravel() sedapat mungkin mengembalikan view sedangkan flatten() selalu mengembalikan salinan. Pembahasan mencakup penggunaan dasar keduanya, urutan memori C dan F yang menentukan urutan elemen hasil perataan, serta kondisi yang membuat ravel() kehilangan sifat view-nya.
Mengubah array menjadi satu dimensi#
Perataan (flatten) adalah operasi menyusun seluruh elemen array berdimensi dua ke atas menjadi satu deretan. NumPy menyediakan dua cara yang hasilnya identik untuk array biasa, yaitu ravel() dan flatten(). Keduanya membaca elemen baris demi baris sesuai urutan memori C.
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.ravel())
print(a.flatten())[1 2 3 4 5 6]
[1 2 3 4 5 6]Kedua pemanggilan menghasilkan array satu dimensi berisi enam elemen dengan urutan yang sama, yaitu 1 sampai 6. Metode ravel() juga tersedia sebagai fungsi np.ravel(a), sehingga keduanya dapat dipanggil sesuai gaya kode yang sedang ditulis. Karena bentuk hasilnya selalu satu dimensi, operasi ini sering digunakan sebagai langkah penyiapan sebelum data diolah oleh fungsi yang menuntut masukan deretan datar.
Perbedaan keduanya tidak terletak pada hasil, melainkan pada ikatan memori hasil terhadap array asalnya. Perbedaan tersebut baru terasa ketika array hasil perataan akan dimutasi atau disimpan untuk waktu lama, karena ikatan memori menentukan data mana yang ikut berubah.
ravel sebagai view, flatten sebagai salinan#
Metode ravel() mengembalikan view apabila susunan memori array asalnya mengizinkan, sedangkan flatten() tanpa syarat selalu mengembalikan salinan. Karena view berbagi buffer data dengan asalnya, mutasi pada hasil ravel() terbawa ke array asal, sedangkan mutasi pada hasil flatten() tidak pernah terbawa. Fungsi np.shares_memory membedakan keduanya secara langsung. Keduanya juga menerima parameter order yang sama untuk memilih urutan pembacaan elemen, tetapi pembeda utama keduanya tetap sifat keluarannya, yaitu view dan salinan.
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
r = a.ravel()
f = a.flatten()
print(np.shares_memory(a, r))
print(np.shares_memory(a, f))True
FalseKeluaran True pada baris pertama menegaskan bahwa r berbagi memori dengan a, sedangkan False pada baris kedua menegaskan bahwa f berdiri sendiri. Aturan ini menjadikan flatten() pilihan yang aman ketika hasil perataan akan dimodifikasi, dan ravel() pilihan yang hemat ketika perataan hanya dilakukan untuk dibaca. Biaya salinan pada array besar bukan perkara kecil, sehingga pemilihan yang sadar berdampak langsung pada penggunaan memori program. Perbedaan ini juga terasa ketika perataan hanya menjadi langkah antara, misalnya sebelum data dipakai pustaka lain yang menuntut array satu dimensi, karena memilih ravel() menghindari satu salinan penuh pada data yang tidak akan diubah.
Urutan memori C dan F#
Urutan elemen hasil perataan ditentukan oleh urutan memori yang digunakan saat membaca array. NumPy mengenal dua urutan, yaitu urutan C (C order) yang membaca array sepanjang baris dan urutan F (F order) yang membacanya sepanjang kolom. Keduanya dinamai menurut konvensi bahasa C dan Fortran dalam penyimpanan matriks.
Diagram di atas memperlihatkan array yang sama yang dibaca dengan dua urutan. Pada urutan C, pembacaan bergerak ke kanan sepanjang baris pertama sebelum turun ke baris kedua. Pada urutan F, pembacaan bergerak ke bawah sepanjang kolom pertama sebelum pindah ke kolom kedua.
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.ravel())
print(a.ravel(order="F"))[1 2 3 4 5 6]
[1 4 2 5 3 6]Parameter order menentukan urutan pembacaan pada saat perataan dilakukan, dan nilai bawaannya adalah "C". Urutan F menghasilkan deretan 1, 4, 2, 5, 3, 6 karena kolom pertama dibaca lebih dahulu. Metode flatten() menerima parameter order yang sama, tetapi sifat salinannya tetap berlaku untuk kedua urutan.
Kapan ravel membuat salinan#
Sifat view pada ravel() berlaku dengan syarat, yaitu array asal harus dapat dibaca sebagai satu deretan berurutan. Apabila syarat itu gagal, ravel() senyap mengembalikan salinan, sama seperti flatten(). Kasus yang paling sering adalah array hasil transpose, karena susunan memorinya kolom demi kolom.
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
t = a.T
r = t.ravel()
print(np.shares_memory(a, r))FalseArray t adalah transpose dari a, dan np.shares_memory(a, r) melaporkan False, yang berarti perataan ini membangun buffer baru. Tidak ada peringatan yang menyertai perubahan perilaku ini, sehingga kode yang mengandalkan ikatan memori hasil ravel() berisiko gagal diam-diam. Pemeriksaan np.shares_memory tetap menjadi alat penentu apabila ikatan memori memang penting bagi kebenaran program.
Kesalahan umum#
Kesalahan pertama adalah memutasi hasil flatten() sambil mengharapkan array asal ikut berubah. Karena hasilnya selalu salinan, mutasi tersebut hanya menyentuh buffer baru.
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
f = a.flatten()
f[0] = 99
print(a[0, 0])1Nilai a[0, 0] tetap 1 karena f tidak berbagi memori dengan a. Perbaikannya adalah menggunakan ravel() apabila perubahan memang dimaksudkan terbawa, atau menuliskan kembali hasil perataan ke array asal melalui penugasan.
Kesalahan kedua adalah kebalikannya, yaitu memperlakukan hasil ravel() sebagai data yang berdiri sendiri.
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
r = a.ravel()
r[0] = 99
print(a[0, 0])99Kali ini nilai a[0, 0] ikut menjadi 99 karena r berbagi buffer dengan a. Kedua contoh menunjukkan bahwa pilihan antara ravel() dan flatten() adalah keputusan tentang memori, bukan sekadar dua nama untuk operasi yang sama. Apabila keinginannya tidak pasti, flatten() menyatakan salinan secara eksplisit sehingga perilakunya tidak bergantung pada susunan memori array asal.
Ringkasan#
ravel()danflatten()menghasilkan array satu dimensi yang isinya sama, dengan pembacaan baris demi baris pada urutan bawaan C.ravel()mengembalikan view apabila memungkinkan, sedangkanflatten()selalu mengembalikan salinan.- Parameter
order="F"mengubah urutan pembacaan menjadi sepanjang kolom, sehingga hasil perataannya berbeda secara deterministik. - Pada array hasil transpose,
ravel()kehilangan sifat view dan mengembalikan salinan, sehingga ikatan memori wajib diperiksa dengannp.shares_memoryapabila penting.
Referensi#
- numpy.ravel — NumPy — Dokumentasi ravel beserta parameter order dan syarat view pada hasilnya.
- Copies and views — NumPy — Penjelasan resmi kapan NumPy membuat view dan kapan salinan dibuat.