Menyalin array berarti mengalokasikan blok baru lalu memindahkan seluruh byte-nya — pada data besar, operasi ini jauh lebih mahal daripada operasi aritmetika itu sendiri. Masalahnya, beberapa pemanggilan fungsi menyalin data tanpa memberi tanda, dan kebiasaan defensif seperti “buat saja salinannya” membuat program memboros memori dan waktu.
Kabar baiknya: status view atau copy dapat dibuktikan, bukan ditebak. Alat utamanya adalah np.shares_memory, yang memeriksa apakah dua array menunjuk blok memori yang sama. Bab ini membedah fungsi-fungsi yang sering dipakai dan status salinannya.
asarray vs array #
np.array secara bawaan selalu menyalin, sedangkan np.asarray menyalin hanya bila perlu — ketika diberi objek yang bukan array. Untuk input yang sudah berupa ndarray, np.asarray mengembalikan objek yang sama:
import numpy as np
data = np.arange(5)
a = np.array(data)
b = np.asarray(data)
print("np.array(ndarray) :", np.shares_memory(a, data))
print("np.asarray(ndarray) :", np.shares_memory(b, data))Output yang Dihasilkan:
np.array(ndarray) : False
np.asarray(ndarray) : TrueCara membacanya:
- Baris 4 (
np.array(data)): argumencopy=Truebawaan membuat NumPy mengalokasikan blok baru, sekalipun inputnya sudah array dengan dtype yang sama. - Baris 5 (
np.asarray(data)): karena input sudah ndarray dan tidak ada permintaan dtype lain, fungsi mengembalikan objek yang sama persis. - Kedua baris
print:Falseberarti salinan penuh;Trueberarti view — bukti nyata, bukan asumsi.
Kebiasaan yang aman: pakai np.asarray pada batas fungsi yang menerima “array-like”, sehingga pemanggil yang sudah membawa ndarray tidak kena biaya salinan.
ravel vs flatten #
Kedua fungsi menghasilkan array 1-D, tetapi keduanya berbeda sikap terhadap memori:
import numpy as np
a = np.arange(12).reshape(3, 4)
f = a.flatten()
r = a.ravel()
print("flatten shares:", np.shares_memory(f, a))
print("ravel shares:", np.shares_memory(r, a))Output yang Dihasilkan:
flatten shares: False
ravel shares: True- Baris 4 (
flatten): fungsi ini menjamin salinan baru dalam urutan C, apa pun kondisi array asalnya — aman, tetapi selalu berbayar. - Baris 5 (
ravel): fungsi ini mengembalikan view bila memungkinkan dan menyalin hanya bila array aslinya non-contiguous (lihat Chapter Contiguous vs Non-contiguous).
astype dengan copy=False #
astype bawaannya juga selalu menyalin. Argumen copy=False mengubahnya menjadi “salin hanya bila dtype harus berubah”:
import numpy as np
a = np.arange(5, dtype=np.int64)
sama = a.astype(np.int64, copy=False)
beda = a.astype(np.float64, copy=False)
print("dtype sama :", np.shares_memory(sama, a))
print("dtype beda :", np.shares_memory(beda, a))Output yang Dihasilkan:
dtype sama : True
dtype beda : False- Baris 4 (
astype(np.int64, copy=False)): dtype tujuan sama dengan dtype asal, sehingga tidak ada pekerjaan konversi — NumPy mengembalikan array asli. - Baris 5 (
astype(np.float64, copy=False)): menyimpanint64sebagaifloat64butuh ukuran penyimpanan berbeda, maka salinan tetap dibuat.
Pola copy=False menjadikan fungsi konversi hemat: ia hanya membayar bila memang perlu.
fancy Indexing Selalu Menyalin #
Berbeda dari slicing biasa, fancy indexing — mengindeks dengan list atau array bilangan bulat — selalu menghasilkan salinan, karena urutan dan jumlah elemennya bisa apa saja:
import numpy as np
a = np.arange(10)
fancy = a[[1, 3, 5]]
irisan = a[1:6:2]
print("fancy indexing :", np.shares_memory(fancy, a))
print("slice biasa :", np.shares_memory(irisan, a))
print(np.array_equal(fancy, irisan))Output yang Dihasilkan:
fancy indexing : False
slice biasa : True
True- Baris 4 vs 5: keduanya memilih elemen bernilai sama (baris terakhir membuktikannya dengan
np.array_equalyang mengembalikanTrue), tetapifancyadalah salinan sedangkanirisanview. - Implikasi: mengubah
fancytidak memengaruhia; mengubahirisanmengubaha. Perilaku lengkapnya dibahas pada Chapter Fancy Indexing dan Boolean Indexing.
Hasil filtering dengan mask boolean berperilaku sama seperti fancy indexing — salinan baru:
import numpy as np
a = np.arange(10)
hasil = a[a % 2 == 0]
print("shares_memory:", np.shares_memory(hasil, a))
hasil[0] = 999
print("array asli :", a[0])Output yang Dihasilkan:
shares_memory: False
array asli : 0- Baris 4 (
a[a % 2 == 0]): hasil filtering bernilaiFalsepadashares_memory— data baru terpisah daria. - Baris 5-6: karena terpisah, mengubah
hasil[0]menjadi999tidak menyentuha, dana[0]tetap0.
| Operasi | Hasil | Kapan menyalin |
|---|---|---|
np.array(x) | selalu copy | selalu (bila copy=True) |
np.asarray(x) | view bila bisa | hanya saat input bukan ndarray |
a[1:5] | view | tidak pernah |
a[[1, 3, 5]] | selalu copy | selalu |
a[mask] | selalu copy | selalu |
a.ravel() | view bila bisa | saat non-contiguous |
a.flatten() | selalu copy | selalu |
a.astype(t) | copy | bila dtype berubah; copy=False bila tidak |