Python Numpy
Numpy merupakan pustaka utama untuk komputasi sains/ilmiah dengan Python. Numpy menyediakan objek dan fasilitas pengolahan/operasi untuk array multidimensi (seperti yang tersedia di MATLAB).
Array
- Array dalam numpy adalah kumpulan nilai, berjenis sama, dan diindeks oleh tuple integer nonnegatif.
- Jumlah dimensi adalah rank dari array; shape dari array adalah tuple dari integer yang memberikan ukuran (size) dari array di setiap dimensinya.
- Kita dapat menginisialisasi numpy array dengan nested list, dan mengakses elemen menggunakan notasi kurung siku (seperti lazimnya list).
- Numpy juga menyediakan fungsi-fungsi untuk membentuk dan melakukan operasi pada array.
import numpy as np
a = np.array([1, 2, 3]) # Create a rank 1 array
print(type(a)) # Prints "<type 'numpy.ndarray'>"
print(a.shape) # Prints "(3,)"
print(a[0], a[1], a[2]) # Prints "1 2 3"
a[0] = 5 # Change an element of the array
print(a) # Prints "[5, 2, 3]"
b = np.array([[1,2,3],[4,5,6]]) # Create a rank 2 array
print(b.shape) # Prints "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0]) # Prints "1 2 4"
# -----
a = np.zeros((2,2)) # Create an array of all zeros
print(a) # Prints "[[ 0. 0.]
# [ 0. 0.]]"
b = np.ones((1,2)) # Create an array of all ones
print(b) # Prints "[[ 1. 1.]]"
c = np.full((2,2), 7) # Create a constant array
print(c) # Prints "[[ 7. 7.]
# [ 7. 7.]]"
d = np.eye(2) # Create a 2x2 identity matrix
print(d) # Prints "[[ 1. 0.]
# [ 0. 1.]]"
e = np.random.random((2,2)) # Create an array filled with random values
print(e) # Might print "[[ 0.91940167 0.08143941]
# [ 0.68744134 0.87236687]]"
Array Indexing dan Slicing
Numpy memberikan beberapa alternatif untuk mengakses elemen dalam array.
Serupa dengan list, numpy array dapat di-slice.
Karena array dapat mempunyai lebih dari satu dimensi, kita harus melakukan slice untuk setiap dimensi array.
import numpy as np
# Create the following rank 2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
# [[2 3]
# [6 7]]
b = a[:2, 1:3]
# A slice of an array is a view into the same data, so modifying it
# will modify the original array.
print a[0, 1] # Prints "2"
b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1]
print a[0, 1] # Prints "77"
Kita juga bisa mengkombinasikan integer dengan slice indexing. Operasi ini akan menghasilkan array dengan rank yang lebih rendah dari array aslinya.
import numpy as np
# Create the following rank 2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
# Two ways of accessing the data in the middle row of the array.
# Mixing integer indexing with slices yields an array of lower rank,
# while using only slices yields an array of the same rank as the
# original array:
row_r1 = a[1, :] # Rank 1 view of the second row of a
row_r2 = a[1:2, :] # Rank 2 view of the second row of a
print row_r1, row_r1.shape # Prints "[5 6 7 8] (4,)"
print row_r2, row_r2.shape # Prints "[[5 6 7 8]] (1, 4)"
# We can make the same distinction when accessing columns of an array:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print col_r1, col_r1.shape # Prints "[ 2 6 10] (3,)"
print col_r2, col_r2.shape # Prints "[[ 2]
# [ 6]
# [10]] (3, 1)"
Integer Array Indexing
Saat kita mengindeks menjadi numpy array menggunakan slicing, array yang dihasilkan akan selalu berupa subarray dari array aslinya.
Sebaliknya, integer array indexing memungkinkan kita membuat sembarang array menggunakan data dari array lain.
import numpy as np
a = np.array([[1,2], [3, 4], [5, 6]])
# An example of integer array indexing.
# The returned array will have shape (3,)
print a[[0, 1, 2], [0, 1, 0]] # Prints "[1 4 5]"
# The above example of integer array indexing is equivalent to this:
print np.array([a[0, 0], a[1, 1], a[2, 0]]) # Prints "[1 4 5]"
# When using integer array indexing, you can reuse the same
# element from the source array:
print a[[0, 0], [1, 1]] # Prints "[2 2]"
# Equivalent to the previous integer array indexing example
print np.array([a[0, 1], a[0, 1]]) # Prints "[2 2]"
Boolean Array Indexing
Boolean Array Indexing memungkinkan kita memilih sembarang elemen dari array.
Seringkali, jenis pengindeksan ini digunakan untuk memilih elemen dari array yang memenuhi beberapa kondisi/kriteria.
import numpy as np
a = np.array([[1,2], [3, 4], [5, 6]])
bool_idx = (a > 2) # Find the elements of a that are bigger than 2;
# this returns a numpy array of Booleans of the same
# shape as a, where each slot of bool_idx tells
# whether that element of a is > 2.
print bool_idx # Prints "[[False False]
# [ True True]
# [ True True]]"
# We use boolean array indexing to construct a rank 1 array
# consisting of the elements of a corresponding to the True values
# of bool_idx
print a[bool_idx] # Prints "[3 4 5 6]"
# ---
# We can do all of the above in a single concise statement:
print a[a > 2] # Prints "[3 4 5 6]"
Tipe Data
Setiap numpy array adalah kumpulan elemen berjenis sama.
Numpy menyediakan sejumlah tipe data numerik yang dapat digunakan untuk mengkonstruksi array.
Numpy mencoba menentukan (menebak) tipe data saat array dibuat. Fungsi-fungsi untuk membuat array biasanya juga menyertakan argumen opsional untuk menentukan tipe data secara eksplisit.
import numpy as np
x = np.array([1, 2]) # Let numpy choose the datatype
print x.dtype # Prints "int64"
x = np.array([1.0, 2.0]) # Let numpy choose the datatype
print x.dtype # Prints "float64"
x = np.array([1, 2], dtype=np.int64) # Force a particular datatype
print x.dtype # Prints "int64"
Operasi Matematika pada Array
Fungsi/operator matematika dasar pada array beroperasi per-elemen (elementwise). Operasi bisa melalui fungsi (modul numpy) atau melalui operator overload.
import numpy as np
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)
# Elementwise sum; both produce the array
# [[ 6.0 8.0]
# [10.0 12.0]]
print x + y
print np.add(x, y)
# Elementwise difference; both produce the array
# [[-4.0 -4.0]
# [-4.0 -4.0]]
print x - y
print np.subtract(x, y)
# Elementwise product; both produce the array
# [[ 5.0 12.0]
# [21.0 32.0]]
print x * y
print np.multiply(x, y)
# Elementwise division; both produce the array
# [[ 0.2 0.33333333]
# [ 0.42857143 0.5 ]]
print x / y
print np.divide(x, y)
# Elementwise square root; produces the array
# [[ 1. 1.41421356]
# [ 1.73205081 2. ]]
print np.sqrt(x)
Perhatikan bahwa tidak seperti MATLAB, *
adalah perkalian elemen, bukan perkalian matriks.
Sebagai gantinya, kita menggunakan dot function untuk menghitung vektor inner product, mengalikan vektor dengan matriks, dan perkalian antar matriks.
Dot tersedia baik sebagai fungsi (modul numpy) maupun sebagai instance method dari objek array
import numpy as np
x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])
v = np.array([9,10])
w = np.array([11, 12])
# Inner product of vectors; both produce 219
print v.dot(w)
print np.dot(v, w)
# Matrix / vector product; both produce the rank 1 array [29 67]
print x.dot(v)
print np.dot(x, v)
# Matrix / matrix product; both produce the rank 2 array
# [[19 22]
# [43 50]]
print x.dot(y)
print np.dot(x, y)
Numpy menyediakan banyak fungsi untuk melakukan komputasi pada array; salah satu yang paling berguna adalah sum (penjumlahan seluruh elemen).
Selain menghitung fungsi matematika menggunakan array, kita sering kali perlu melakukan reshape atau memanipulasi data dalam array.
Contoh sederhana dari jenis operasi ini adalah transpose matriks, dengan cukup menggunakan atribut T
dari objek array.
import numpy as np
x = np.array([[1,2],[3,4]])
print np.sum(x) # Compute sum of all elements; prints "10"
print np.sum(x, axis=0) # Compute sum of each column; prints "[4 6]"
print np.sum(x, axis=1) # Compute sum of each row; prints "[3 7]"
import numpy as np
x = np.array([[1,2], [3,4]])
print x # Prints "[[1 2]
# [3 4]]"
print x.T # Prints "[[1 3]
# [2 4]]"
# Note that taking the transpose of a rank 1 array does nothing:
v = np.array([1,2,3])
print v # Prints "[1 2 3]"
print v.T # Prints "[1 2 3]"
Broadcasting
Broadcasting adalah mekanisme yang memungkinkan numpy untuk melakukan operasi aritmetika pada array yang berbeda shape.
Seringkali kita memiliki array yang shape-nya berbeda, dan kita ingin menggunakan array yang shape-nya lebih kecil beberapa kali untuk melakukan operasi dengan array yang shape-nya lebih besar.
Contoh kasus misalnya, kita ingin menambahkan vektor konstanta ke setiap baris dalam sebuah matriks.
import numpy as np
# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = np.empty_like(x) # Create an empty matrix with the same shape as x
# Add the vector v to each row of the matrix x with an explicit loop
for i in range(4):
y[i, :] = x[i, :] + v
# Now y is the following
# [[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]
print y
Mekanisme manual seperti di atas dapat saja dilakukan, namun ketika matriks x
sangat besar, menggunakan loop eksplisit dengan Python bisa jadi sangat lambat.
Perhatikan bahwa menambahkan vektor v
ke setiap baris dari matriks x
sama dengan membentuk matriks vv
dengan menumpuk banyak salinan v
secara vertikal, kemudian melakukan penjumlahan per-elemen dari x
dan vv
.
import numpy as np
# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
vv = np.tile(v, (4, 1)) # Stack 4 copies of v on top of each other
print vv # Prints "[[1 0 1]
# [1 0 1]
# [1 0 1]
# [1 0 1]]"
y = x + vv # Add x and vv elementwise
print y # Prints "[[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]"
Numpy broadcasting memungkinkan kita melakukan penghitungan seperti ini tanpa harus membuat banyak salinan dari v.
Berikut versi yang menggunakan broadcasting.
Ekspresi y = x + v
menghasilkan hasil yang sesuai, meskipun x
mempunyai shape (4, 3)
dan v
(3,)
. Hal ini karena mekanisme broadcasting.
Ekspresi tersebut diartikan seolah-olah v
benar-benar memiliki shape (4, 3)
, di mana setiap baris adalah salinan dari v
, dan penjumlahan dilakukan per-elemen.
import numpy as np
# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v # Add v to each row of x using broadcasting
print y # Prints "[[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]"
Mekanisme broadcasting dua buah array mengikuti aturan berikut:
- Jika array tidak memiliki rank yang sama, tambahkan shape array yg rank-nya lebih kecil dengan
1s
hingga kedua shape memiliki panjang yang sama. - Kedua array dikatakan kompatibel dalam sebuah dimensi jika keduanya memiliki ukuran yang sama dalam dimensi tersebut, atau jika salah satu array memiliki ukuran
1
dalam dimensi tersebut. - Broadcasting dapat dilakukan kedua array jika kompatibel di semua dimensi.
- Setelah broadcasting, setiap array berperilaku seolah-olah memiliki shape identik dengan shape maksimum per-elemen dari kedua array input.
- Dalam dimensi di mana satu array berukuran
1
dan array lainnya berukuran lebih besar dari1
, array pertama berperilaku seolah-olah disalin sepanjang dimensi itu.
import numpy as np
# Compute outer product of vectors
v = np.array([1,2,3]) # v has shape (3,)
w = np.array([4,5]) # w has shape (2,)
# To compute an outer product, we first reshape v to be a column
# vector of shape (3, 1); we can then broadcast it against w to yield
# an output of shape (3, 2), which is the outer product of v and w:
# [[ 4 5]
# [ 8 10]
# [12 15]]
print np.reshape(v, (3, 1)) * w
# Add a vector to each row of a matrix
x = np.array([[1,2,3], [4,5,6]])
# x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3),
# giving the following matrix:
# [[2 4 6]
# [5 7 9]]
print x + v
# .....
Fungsi yang mendukung fitur broadcasting disebut sebagai fungsi universal.
Broadcasting biasanya membuat kode menjadi lebih ringkas dan cepat (karena operasi paralel). Untuk proses komputasi yang intensif, penggunaan operasi array multidimensi dengan broadcasting sangat dianjurkan, jika memungkinkan.
# .....
# Add a vector to each column of a matrix
# x has shape (2, 3) and w has shape (2,).
# If we transpose x then it has shape (3, 2) and can be broadcast
# against w to yield a result of shape (3, 2); transposing this result
# yields the final result of shape (2, 3) which is the matrix x with
# the vector w added to each column. Gives the following matrix:
# [[ 5 6 7]
# [ 9 10 11]]
print (x.T + w).T
# Another solution is to reshape w to be a row vector of shape (2, 1);
# we can then broadcast it directly against x to produce the same
# output.
print x + np.reshape(w, (2, 1))
# Multiply a matrix by a constant:
# x has shape (2, 3). Numpy treats scalars as arrays of shape ();
# these can be broadcast together to shape (2, 3), producing the
# following array:
# [[ 2 4 6]
# [ 8 10 12]]
print x * 2