Broadcasting dalam NumPy
Broadcasting adalah aturan NumPy untuk menggabungkan array dengan shape berbeda yang kompatibel. Dimensi berukuran satu diperlakukan seolah-olah ukurannya sama dengan ukuran dimensi yang bersesuaian pada array lain, tanpa menyalin data ke array yang lebih besar.
Vektorisasi memungkinkan satu ekspresi bekerja pada seluruh array. NumPy menjalankan loop di baliknya dalam kode terkompilasi yang telah dioptimalkan, sehingga sering lebih cepat daripada loop Python eksplisit.
import numpy as np
# Membuat dua array
a = np.array([0, 1, 2])
b = np.array([2, 2, 2])
# Operasi vektorisasi (elemen per elemen)
hasil = a + b
print(hasil)
# Output: [2 3 4]Pada contoh di atas, NumPy menjumlahkan elemen-elemen pada posisi yang bersesuaian. Kita cukup menyatakan operasinya sekali tanpa mengindeks setiap elemen dalam loop Python.
Aturan Broadcasting
Dua array bisa digabungkan tanpa loop eksplisit ketika NumPy sanggup menyejajarkan dimensinya sendiri. Untuk menentukan apakah dua shape kompatibel, NumPy membandingkan dimensinya dari kanan ke kiri dan berhenti pada pasangan pertama yang tidak bisa disejajarkan.
Tiga aturan menutup semua kemungkinan. Tabel di bawah ini menyebutkan syarat yang diperiksa setiap aturan beserta hasil yang NumPy keluarkan untuk syarat tersebut.
| Aturan | Syarat pada shape | Yang NumPy lakukan |
|---|---|---|
| Aturan | Kedua shape punya jumlah dimensi yang berbeda | NumPy menambahkan dimensi berukuran di sebelah kiri shape yang lebih pendek |
| Aturan | Sebuah pasangan sejajar berukuran sama, atau salah satu sisinya berukuran | Ukuran yang sama langsung cocok. Dimensi berukuran satu dipakai ulang secara konseptual tanpa membuat salinan berulang |
| Aturan | Sebuah pasangan sejajar berukuran berbeda dan tidak ada sisi yang berukuran | NumPy menghasilkan ValueError |
Array dengan Skalar
Broadcasting juga berlaku antara array dan satu bilangan. NumPy melebarkan skalar itu ke setiap elemen, sehingga kamu tidak perlu menulis loop.
import numpy as np
# Array 1D dengan skalar
a = np.arange(3) # [0, 1, 2]
b = 5
hasil = a + b
print(f"Array a: {a}")
print(f"Skalar b: {b}")
print(f"Hasil a + b: {hasil}")
# Penjelasan bentuk:
# a memiliki bentuk (3,)
# b memiliki bentuk () - skalar
# Setelah broadcasting: b menjadi [5, 5, 5]
# Output: [5 6 7]Array Dua Dimensi dengan Array Satu Dimensi
Jika dua array memiliki bentuk berbeda yang masih kompatibel, NumPy dapat menyesuaikannya secara otomatis melalui broadcasting. Dengan cara ini, satu operasi dapat diterapkan ke setiap baris atau kolom tanpa menyalin nilai secara manual.
import numpy as np
# Array 2D dengan array 1D
a = np.ones((3, 3)) # Matriks 3x3 berisi angka 1
b = np.arange(3) # [0, 1, 2]
hasil = a + b
print("Array a (3x3):")
print(a)
print(f"Array b (1D): {b}")
print("Hasil a + b:")
print(hasil)
# Broadcasting terjadi:
# a: bentuk (3, 3)
# b: bentuk (3,) -> diperluas menjadi (1, 3) -> (3, 3)
# b ditambahkan ke setiap baris dari aKasus Broadcasting Gagal
Pada shape (2, 3) dan (2,), dimensi terakhir tidak cocok: ukurannya 3 dan 2, dan tidak ada yang bernilai 1. NumPy menghasilkan ValueError sebelum penjumlahan dilakukan.
import numpy as np
try:
# Array dengan bentuk yang tidak kompatibel
a = np.arange(6).reshape(2, 3) # bentuk (2, 3)
b = np.arange(2) # bentuk (2,)
print(f"Array a bentuk: {a.shape}")
print(f"Array b bentuk: {b.shape}")
# Ini akan menghasilkan error
hasil = a + b
except ValueError as e:
print(f"Error: {e}")
print("Bentuk array tidak kompatibel untuk broadcasting")Operasi Aritmetika Array
Operator aritmetika NumPy bekerja elemen per elemen, kecuali operasi yang memang memiliki semantik lain, seperti perkalian matriks.
Ketika array digabungkan dengan skalar, broadcasting menerapkan skalar itu pada setiap elemen. Kita tidak perlu menulis indexing loop secara manual.
import numpy as np
a = np.array([0, 1, 2, 3, 4])
# Penjumlahan dengan skalar
print("Penjumlahan:")
print(f"a + 1 = {a + 1}")
# Output: [1 2 3 4 5]
# Perkalian dengan skalar
print("Perkalian:")
a *= 2
print(f"a *= 2: {a}")
# Output: [0 2 4 6 8]
# Pangkat
print("Pangkat:")
print(f"2**a = {2**a}")
# Output: [ 1 4 16 64 256]Operasi Antar Array
import numpy as np
a = np.array([0, 1, 2, 3, 4])
b = np.array([4, 3, 2, 1, 0])
# Pengurangan elemen per elemen
print("Pengurangan:")
print(f"a - b = {a - b}")
# Output: [-4 -2 0 2 4]
# Perkalian elemen per elemen
print("Perkalian elemen per elemen:")
print(f"a * b = {a * b}")
# Output: [0 3 4 3 0]
# Perkalian matriks (dot product)
print("Perkalian matriks:")
print(f"a @ b = {a @ b}")
# Output: 10Operator * mengalikan elemen pada posisi yang sama. Untuk dua array satu dimensi di atas, @ menghasilkan hasil kali titik: 0 + 3 + 4 + 3 + 0 sama dengan 10. Untuk dua matriks, @ memakai aturan baris dikalikan kolom. Jangan menyamakan np.dot() dengan @ untuk semua bentuk array. Aturan keduanya berbeda pada dimensi yang lebih tinggi.
Perbandingan dan Logika
Operasi perbandingan NumPy menghasilkan array boolean. Gunakan array tersebut untuk menyaring data atau menggabungkan beberapa kondisi.
import numpy as np
a = np.array([0, 1, 2, 3, 4])
b = np.array([0, 0, 2, 4, 4])
# Operasi perbandingan
print("Perbandingan lebih besar:")
print(f"a > 2: {a > 2}")
# Output: [False False False True True]
print("Perbandingan sama dengan:")
print(f"a == b: {a == b}")
# Output: [ True False True False True]
# Operasi logika
print("Operasi logika OR:")
print(f"(a > 2) | (a == b): {(a > 2) | (a == b)}")
# Output: [ True False True True True]Untuk logika boolean elemen per elemen, gunakan ~ untuk NOT, & untuk AND, dan | untuk OR, atau fungsi np.logical_* yang sesuai. Beri tanda kurung pada setiap perbandingan karena prioritas operatornya berbeda. Operator skalar Python not, and, dan or tidak menjalankan logika array secara elemen per elemen.
Fungsi Statistik dan Reduksi
Fungsi reduksi menggabungkan banyak elemen menjadi lebih sedikit nilai. Tanpa axis, seluruh array dapat direduksi menjadi satu nilai. Dengan axis, hanya dimensi tersebut yang direduksi. Pada tabel nilai ujian, hasilnya dapat berupa rata-rata per mata pelajaran atau per siswa.
NumPy menyediakan fungsi statistik untuk menghitung ringkasan seperti jumlah, rata-rata, dan simpangan baku. Setiap fungsi dapat diterapkan pada seluruh array atau sumbu tertentu.
import numpy as np
# Membuat array 2D untuk contoh
data = np.array([[3, 0, -1, 1],
[2, -1, -2, 4],
[1, 7, 0, 4]])
print("Data array:")
print(data)
# Statistik pada seluruh array
print(f"Jumlah total: {np.sum(data)}")
print(f"Rata-rata: {np.mean(data):.2f}")
print(f"Nilai minimum: {np.min(data)}")
print(f"Nilai maksimum: {np.max(data)}")
print(f"Standar deviasi: {np.std(data):.2f}")
# Output:
# Jumlah total: 18
# Rata-rata: 1.50
# Nilai minimum: -2
# Nilai maksimum: 7
# Standar deviasi: 2.50Operasi dengan Sumbu
Pada array dua dimensi, axis=0 mereduksi dimensi baris dan menghasilkan satu nilai per kolom. axis=1 mereduksi dimensi kolom dan menghasilkan satu nilai per baris.
Sumbu yang dipilih menentukan dimensi yang direduksi oleh fungsi statistik. Pada data penjualan bulanan untuk beberapa produk, satu sumbu dapat menghasilkan total per produk dan sumbu lainnya menghasilkan total per bulan.
import numpy as np
data = np.array([[3, 0, -1, 1],
[2, -1, -2, 4],
[1, 7, 0, 4]])
# Operasi sepanjang axis=0 (untuk setiap kolom)
print("Maksimum setiap kolom (axis=0):")
print(f"max(axis=0): {np.max(data, axis=0)}")
# Output: [3 7 0 4]
print("Indeks maksimum setiap kolom:")
print(f"argmax(axis=0): {np.argmax(data, axis=0)}")
# Output: [0 2 2 1]
# Operasi sepanjang axis=1 (untuk setiap baris)
print("Maksimum setiap baris (axis=1):")
print(f"max(axis=1): {np.max(data, axis=1)}")
# Output: [3 4 7]
print("Indeks maksimum setiap baris:")
print(f"argmax(axis=1): {np.argmax(data, axis=1)}")
# Output: [0 3 1]Manipulasi Bentuk Array
Operasi shape mengubah cara elemen-elemen yang sama diindeks. Reshape mempertahankan jumlah elemen, tetapi menempatkannya ke dalam susunan dimensi yang berbeda.
Array NumPy yang baru dibuat biasanya tersimpan berurutan dengan tata letak C-contiguous. Dalam tata letak ini, indeks terakhir berubah paling cepat saat data dibaca dari memori. Hasil slicing atau transpose dapat merujuk ke data yang sama dengan jarak antarelemen memori yang berbeda. Karena itu, perhatikan argumen order dan atribut strides saat memakai reshape() atau flatten().
import numpy as np
# Membuat array 2D
a = np.array([[0, 1], [2, 3]])
print("Array 2D:")
print(a)
print(f"Bentuk: {a.shape}")
# Melihat bagaimana disimpan dalam memori
print(f"Disimpan dalam memori sebagai: {a.ravel()}")
# Output: [0 1 2 3]Flatten dan Ravel
flatten() dan ravel() sama-sama menghasilkan array satu dimensi. flatten() selalu membuat salinan, sedangkan ravel() mengembalikan view jika memungkinkan dan salinan jika tata letak memorinya mengharuskan demikian.
import numpy as np
# Membuat array diagonal
a = np.diag([1, 2, 3])
print("Array diagonal:")
print(a)
# Flatten - membuat salinan independen
b_flatten = a.flatten()
print(f"Hasil flatten: {b_flatten}")
# Mengubah nilai flatten tidak memengaruhi array asli
b_flatten[0] = 9
print(f"Setelah mengubah flatten: {b_flatten}")
print("Array asli tetap sama:")
print(a)
print()
# Ravel - mencoba membuat view tanpa selalu menyalin data
b_ravel = a.ravel()
print(f"Hasil ravel: {b_ravel}")
# Mengubah nilai ravel memengaruhi array asli
b_ravel[0] = 9
print(f"Setelah mengubah ravel: {b_ravel}")
print("Array asli berubah:")
print(a)Reshape dan Resize
reshape() mengubah shape selama jumlah elemennya tetap sama dan mengembalikan view jika memungkinkan. Method ndarray.resize() yang digunakan di bawah mengubah array asli secara langsung.
import numpy as np
# Membuat array diagonal dan flatten
a = np.diag([1, 2, 3])
a_flat = a.flatten()
print(f"Array flat: {a_flat}")
# Reshape - mengubah bentuk dengan jumlah elemen yang sama
b = a_flat.reshape(3, 3)
print("Hasil reshape ke (3,3):")
print(b)
# Mengubah nilai dalam reshape
b[0, 0] = 9
print("Setelah mengubah nilai:")
print(b)
print(f"Array flat asli: {a_flat}") # Berubah karena reshape membuat view
# Resize - mengubah bentuk in-place (tanpa return value)
a_flat.resize(3, 3)
print("Setelah resize:")
print(a_flat) # Sekarang a_flat sudah menjadi 2DTranspose
Transpose menukar urutan axis array. Pada array dua dimensi, baris dan kolom saling bertukar. NumPy menyediakan method transpose() dan atribut .T yang lebih singkat.
import numpy as np
# Membuat array 2x4
a = np.linspace(1, 8, 8).reshape(2, 4)
print("Array asli (2x4):")
print(a)
# Transpose menggunakan method
b = a.transpose()
print("Hasil transpose (4x2):")
print(b)
# Transpose menggunakan atribut .T (lebih singkat)
c = a.T
print("Menggunakan .T:")
print(c)
# Memverifikasi bahwa transpose adalah view
print("Apakah transpose adalah view?", np.shares_memory(a, b))Standardisasi Data dengan Z Score
Standardisasi z-score memusatkan setiap fitur pada rata-rata dan menskalakannya ke standar deviasi . Operasi ini hanya terdefinisi untuk fitur dengan standar deviasi tak nol. Setelah standardisasi, fitur yang semula memakai skala berbeda dapat dibandingkan pada skala yang sama.
Rumus standardisasi z-score adalah , dengan:
- adalah matriks fitur berukuran
- adalah jumlah observasi (baris)
- adalah jumlah fitur (kolom)
- adalah vektor rata-rata untuk setiap kolom
- adalah vektor standar deviasi untuk setiap kolom
import numpy as np
# Membuat data contoh (5 observasi, 3 fitur)
rng = np.random.default_rng(42)
X = rng.standard_normal((5, 3)) * 10 + 50 # Sampel dari distribusi normal dengan mean 50 dan std 10
print("Data asli:")
print(X)
print(f"Bentuk data: {X.shape}")
# Menghitung rata-rata dan standar deviasi setiap kolom
mu = np.mean(X, axis=0) # Rata-rata setiap kolom
sigma = np.std(X, axis=0) # Standar deviasi setiap kolom
print(f"Rata-rata setiap fitur: {mu}")
print(f"Standar deviasi setiap fitur: {sigma}")
# Melakukan standardisasi z-score
Z = (X - mu) / sigma
print("Data setelah standardisasi z-score:")
print(Z)
# Verifikasi hasil standardisasi
print("Verifikasi standardisasi:")
print(f"Rata-rata baru: {np.mean(Z, axis=0)}") # Harus mendekati 0
print(f"Standar deviasi baru: {np.std(Z, axis=0)}") # Harus mendekati 1
# Output standar deviasi baru: [1. 1. 1.]Standardisasi mencegah perbedaan satuan saja menciptakan selisih skala yang besar. Namun, standardisasi tidak menjamin setiap fitur sama penting atau sama berpengaruh karena hal itu tetap ditentukan oleh model dan datanya. Misalnya, tinggi dalam sentimeter dan berat dalam kilogram menjadi sebanding secara numerik setelah distandardisasi.