Array disebut contiguous apabila elemennya berdempetan di memori tanpa celah, tepat seperti urutan yang dijanjikan layoutnya. Masalahnya, operasi sehari-hari seperti slicing kolom dan transpose sering menghasilkan array yang hanya “berpura-pura” multidimensi: data aslinya tetap di tempat, tetapi elemen yang bersebelahan secara logika kini melompat-lompat di memori. Kondisi ini disebut non-contiguous.
Bab ini membahas cara membaca status kontinuitas dari flags, operasi apa yang memutusnya, bagaimana memulihkannya, serta konsekuensi praktisnya — dari perilaku ravel yang berubah hingga salinan yang terjadi tanpa kita sadari.
Mengenali Array Non-contiguous #
Status kontinuitas dibaca dari bendera C_CONTIGUOUS. Kita bandingkan array asli dengan hasil slicing yang mengambil dua kolom sekaligus:
import numpy as np
a = np.arange(12).reshape(3, 4)
s = a[:, ::2]
print("a C_CONTIGUOUS :", a.flags["C_CONTIGUOUS"])
print("s C_CONTIGUOUS :", s.flags["C_CONTIGUOUS"])
print("shares_memory(s,a) :", np.shares_memory(s, a))
print(s)Output yang Dihasilkan:
a C_CONTIGUOUS : True
s C_CONTIGUOUS : False
shares_memory(s,a) : True
[[ 0 2]
[ 4 6]
[ 8 10]]Bedah baris demi baris:
- Baris 3 (
a = ...): array 3x4 dibuat utuh, sehingga dua belas elemennya berdempetan danC_CONTIGUOUSbernilai True. - Baris 4 (
s = a[:, ::2]): slicing dengan langkah dua mengambil kolom 0 dan 2 saja. Karena baris aslinya tetap berisi kolom 1 dan 3 di antaranya, elemensyang bersebelahan terpisah oleh data yang tidak diambil — kontinuitas putus. - Baris 7 (
np.shares_memory):shanyalah view; ia danamenunjuk blok memori yang sama.
Memulihkan Kontinuitas dengan ascontiguousarray #
Cara memulihkan kontinuitas adalah menyalin data ke blok baru yang rapat. Fungsi np.ascontiguousarray melakukannya, dengan satu sifat praktis: bila array sudah contiguous, fungsi ini mengembalikan array asli tanpa menyalin.
import numpy as np
a = np.arange(12).reshape(3, 4)
s = a[:, ::2]
c = np.ascontiguousarray(s)
print("s C_CONTIGUOUS :", s.flags["C_CONTIGUOUS"])
print("c C_CONTIGUOUS :", c.flags["C_CONTIGUOUS"])
print("shares_memory :", np.shares_memory(c, a))Output yang Dihasilkan:
s C_CONTIGUOUS : False
c C_CONTIGUOUS : True
shares_memory : FalseCara membacanya:
- Baris 5 (
np.ascontiguousarray(s)): NumPy mengalokasikan blok baru dan menyalin elemenssecara rapat;ckini sepenuhnya berdiri sendiri. - Baris 8:
ctidak lagi berbagi memori dengana, sehingga perubahan pada satu pihak tidak menular ke pihak lain.
Konsekuensi pada ravel #
Perilaku paling nyata dari array non-contiguous muncul saat kita meratakannya. ravel hanya bisa mengembalikan view bila meratakan berarti menyalin byte secara berurutan; jika tidak, ia diam-diam membuat salinan:
import numpy as np
a = np.arange(12).reshape(3, 4)
baris = a[1]
kolom = a[:, 1]
print("baris C_CONTIGUOUS :", baris.flags["C_CONTIGUOUS"])
print("kolom C_CONTIGUOUS :", kolom.flags["C_CONTIGUOUS"])
print("ravel baris = view :", np.shares_memory(baris.ravel(), a))
print("ravel kolom = copy :", np.shares_memory(kolom.ravel(), a))Output yang Dihasilkan:
baris C_CONTIGUOUS : True
kolom C_CONTIGUOUS : False
ravel baris = view : True
ravel kolom = copy : False- Baris 4 (
baris = a[1]): satu baris utuh adalah potongan memori yang berdempetan, maka statusnya contiguous. - Baris 5 (
kolom = a[:, 1]): satu kolom melompat sepanjang satu baris untuk setiap langkah, maka statusnya non-contiguous. - Baris 6-7:
ravelpadabarismengembalikan view, sedangkanravelpadakolomharus menyalin karena urutan elemen kolom tersebar di memori.
Perilaku ravel dan flatten dibandingkan lebih rinci pada Chapter flatten dan ravel.
transpose: Non-contiguous yang Paling Sering Terjadi #
Hasil .T selalu view tanpa salinan, tetapi hampir selalu non-contiguous untuk matriks C-order. Menariknya, ia justru berstatus F-contiguous karena kolom-kolomnya kini berdempetan:
import numpy as np
a = np.arange(12).reshape(3, 4)
t = a.T
print("t C_CONTIGUOUS :", t.flags["C_CONTIGUOUS"])
print("t F_CONTIGUOUS :", t.flags["F_CONTIGUOUS"])
print("copy C_CONTIGUOUS :", t.copy().flags["C_CONTIGUOUS"])Output yang Dihasilkan:
t C_CONTIGUOUS : False
t F_CONTIGUOUS : True
copy C_CONTIGUOUS : True- Baris 4-5: transpose hanya menukar
shapedanstrides(lihat Chapter Strides dan Memory Access), sehingga status C hilang dan status F muncul. - Baris 6:
copy()menghasilkan blok baru yang kembali rapat dalam urutan C — cara paling umum “merapikan” array hasil transpose.
| Operasi | View atau copy | Status kontinuitas |
|---|---|---|
a[1] (satu baris) | view | C-contiguous |
a[:, 1] (satu kolom) | view | non-contiguous |
a[:, ::2] (langkah dua) | view | non-contiguous |
a.T | view | F-contiguous |
np.ascontiguousarray(s) | copy bila perlu | C-contiguous |
a.copy() | selalu copy | C-contiguous |