Review AI504 Practice Session - 01 NumPy
0. NumPy
행렬이나 일반적으로 대규모 다차원 배열을 쉽게 처리 할 수 있도록 지원하는 파이썬의 라이브러리이다. (출처: 위키피디아)
- How to use?
import numpy as np
1. NumPy array data
- Scalar : single number
- e.g.
a = np.array(1.)
- e.g.
- Vectors : an array of numbers
- e.g.
b = np.array([1., 2., 3.])
- e.g.
- Matrix : 2-D array
- e.g.
c = np.array([[1., 2., 3.], [4., 5., 6.]])
- e.g.
- Tensor : N-dimensional array (n ≥ 2)
- e.g.
d = np.array([[[1., 2., 3.], [4., 5., 6.]], [[7., 8., 9.], [10., 11., 12.]]])
- e.g.
https://hadrienj.github.io/posts/Deep-Learning-Book-Series-2.1-Scalars-Vectors-Matrices-and-Tensors/
Functions
-
.ndim: show dimensione.g.
a.ndim→ 0b.ndim→ 1c.ndim→ 2d.ndim→ 3 -
.shape: show the number of values for each dimensione.g.
a.shape→ ()b.shape→(3,)c.shape→ (2,3)d.shape→ (2, 2, 3)
💡 NOTE : → 뒤는 **출력값(Output)**을 의미
2. Define Numpy arrays
-
np.ones(shape) : define array given shape and fill with 1
e.g. (10,) shape를 가지면서 1으로 채워진 배열을 정의
usage :
np.ones(10) -
np.zeros(shape) : define array given shape and fill with 0
e.g. (2,5) shape를 가지면서 0으로 채워진 배열을 정의
usage :
np.zeros((2,5)) -
np.full(shape, number) : define array given shape and fill with given number
e.g. (2,5) shape를 가지면서 5로 채워진 배열을 정의
usage :
np.full((2,5),5) -
np.random.random(shape) : define array given shape and fill with random numbers
e.g. (2,3,4) shape를 가지는 랜덤 배열 정의
usage :
np.random.random((2, 3, 4)) -
np.arange(number) : define array which contains 0 to given number-1 (similar to python
range())e.g. 0~9로 구성된 배열
usage :
np.arrange(10)→ array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
-
np.arange(number).astype(type) : define arange() array given data type
e.g. float 타입의 0~9로 구성된 배열
usage :
np.arange(10).astype(float)→ array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
-
np.arrange(number).reshape(shape) : define arange() array given shape
e.g.(5, 2) shape를 가지면서 0~9로 구성된 배열
usage :
np.arange(10).reshape((5,2))→ array([[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]])
-
💡 NOTE : shape를 명시할 때, shape가 2-by-3 이면, 괄호까지 포함해서 **(2,3)**로 명시하기!
e.g. 🙅🏻♀️ np.ones(2,3) 🙆🏻♀️ np.ones((2,3))
3. Indexing & Slicing
python에서의 indexing & slicing 과 동일하게 작동한다.
e.g. a = np.arange(10) b = np.arange(9).reshape(3,3)
-
a[index] : access index of a, and index could be < 0
e.g. a의 0번째 인덱스에 있는 값
usage :
a[0]→ 0e.g. a의 뒤에서 4번째에 있는 값
usage :
a[-4]→ 6e.g. 마지막 row
usage :
b[-1]→ [6 7 8]-
Conditional indexing : 조건문에 따른 인덱싱 가능
e.g. 짝수인 값만 출력
idx = b % 2 == 0 # -> [[True False True] # [False True False] # [True False True]] b[idx] # -> [0 2 4 6 8] -
Specific elements from a nd-array
e.g. [0, 2, 3] index에 대한 값 출력 (vector)
idx = [0, 2, 3] a[idx] # [0 2 3]e.g. [0, 2] 행 혹은 열에 해당하는 값 출력 (tensor)
idx = [0, 2] # row b[idx, :] # -> [[0 1 2] # [6 7 8]] # column b[:,idx] # -> [[0 2] # [3 5] # [6 8]]e.g. [[0,0,1],[1,2,0]]에 해당하는 값 출력 (tuple 형태도 가능)
idx = np.array([[0,0,1],[1,2,0]]) # tuple : idx = ((0,0,1),(1,2,0)) b[idx] # -> [[[0 1 2] # [0 1 2] # [3 4 5]] # [[3 4 5] # [6 7 8] # [0 1 2]]]
-
-
a[start index:end index:interval] : access from start index to end index - 1 with interval, and interval could be < 0
e.g. 2번째부터 4번째 인덱스에 있는 값
usage :
a[2:5]→ [2 3 4]e.g. 0번째부터 10번째 인덱스 이전까지 있는 값을 3을 간격으로 출력
usage :
a[0:10:3]→ [0 3 6 9]e.g. 8번째부터 5번째 인덱스 다음까지 있는 값을 -1을 간격으로 출력
usage :
a[8:5:-1]→ [8 7 6]e.g. 두번째 column
usage :
b[:,1]→ [1 4 7]
4. Math Operations
-
Element-wise operation
-
+, - , x, / : given two numpy arrays should have same shape
e.g.
a = np.arange(6).reshape((3, 2)) b = np.full((3,2),2) print(a+b) # -> [[2 3] # [4 5] # [6 7]] print(a-b) # -> [[-2 -1] # [ 0 1] # [ 2 3]] print(a*b) # -> [[ 0 2] # [ 4 6] # [ 8 10]] print(a/b) # -> [[0. 0.5] # [1. 1.5] # [2. 2.5]]
-
-
Unary operation
e.g.
a = np.arange(6).reshape((3,2))-
a.sum(axis) : get sum of a regarding axis (axis is optional)
usage :
a.sum()→ 15e.g. axis 0에 대한 sum (row-wise)
usage :
a.sum(axis=0)→ [6 9]e.g. axis 1에 대한 sum (column-wise)
usage :
a.sum(axis=1)→ [1 5 9] -
a.mean(): get mean of a → 2.5 -
a.max(): get maximum value of a → 5 -
a.min(): get minimum value of a → 0
-
-
Dot product, Multiplication
e.g.
vector :
a = np.arange(3).astype('float')b = np.ones(3)matrix :
a = np.arange(6).reshape((3, 2))b = np.arange(6).reshape((2, 3))tensor :
a = np.arange(24).reshape((4, 3, 2))b = np.ones((4, 2, 3))-
Dot product
usage :
np.dot(a, b)- vector :
np.dot(a, b)→ 3.0 - matrix :
np.dot(a, b).shape→ (3, 3) - tensor :
np.dot(a, b).shape→ (4, 3, 4, 3)
- vector :
-
Mutiplication
usage :
a@b- vector :
a@b→ 3.0 - matrix :
(a@b).shape→ (3, 3) - tensor :
(a@b).shape→ (4, 3, 3)
- vector :
-
5. Shape Manipulation
-
Reshape
usage :
a.reshape(shape)- shape 에서 -1 은 주어진 수가 있을 경우, 현재 shape에서 주어진 수만큼의 모양을 가지고 남는 차원으로 할당하고, 주어진 수가 없을 경우, 1차원 배열로 만든다. 그리고 -1을 통해 가능한 차원 추가는 한 차원 추가만 가능하다.
e.g.
a = np.arange(24) b = a.reshape((6, 4)) print(b.shape) c = a.reshape((6, -1)) print(c.shape) # b와 c의 shape는 (6,4)로 동일 d = a.reshape((6,4,-1)) print(d.shape) # d의 shape는 (6, 4, 1)이 됨 # d = a.reshape((6,4,-1,-1)) -> ValueError: can only specify one unknown dimension e = b.reshape(-1) # e의 shape는 a에서의 shape와 동일하게 (24,)가 됨 -
Add an extra dimension
usage :
a[:, None]- 차원 추가하기 원하는 부분에 None을 입력하고, 기존 값들은 [:] slicing을 통해 복사
e.g.
a = np.arange(3) print(a.shape) # -> (3,) b = a[:, None] print(b) # -> [[0] # [1] # [2]] print(b.shape) # -> (3, 1) c = a[None, :] print(c) # -> [0 1 2] print(c.shape) # -> (1, 3) d = a[:, None, None] print(d.shape) # -> (3, 1, 1) -
Stack, concatenation
-
vstack : stack vertically
usage :
np.vstack(tuple) -
hstack : stack horizontally
usage :
np.vstack(tuple) -
concatenate : concatenate on axis (default axis = 0)
usage :
np.concatenate(tuple, axis)- axis = 0 이면 vstack의 결과와 동일하고, axis = 1 이면 hstack의 결과와 동일
- axis = None 이면 1차원으로 만들어버림
- axis 에 해당하는 dimension을 제외하고 무조건 나머지 input dimension은 동일해야 함!
e.g.
a = np.ones((3,2)) b = np.zeros((3,2)) print(np.vstack([a, b])) # -> [[1. 1.] # [1. 1.] # [1. 1.] # [0. 0.] # [0. 0.] # [0. 0.]] print(np.hstack([a, b])) # -> [[1. 1. 0. 0.] # [1. 1. 0. 0.] # [1. 1. 0. 0.]] print(np.hstack([a, b, a])) # -> [[1. 1. 0. 0. 1. 1.] # [1. 1. 0. 0. 1. 1.] # [1. 1. 0. 0. 1. 1.]] print(np.concatenate([a, b], axis=0)) # -> [[1. 1.] # [1. 1.] # [1. 1.] # [0. 0.] # [0. 0.] # [0. 0.]] print(np.concatenate([a, b], axis=1)) # -> [[1. 1. 0. 0.] # [1. 1. 0. 0.] # [1. 1. 0. 0.]] a = np.ones((4,3,2)) b = np.zeros((5,4,2)) np.concatenate([a,b], axis=2) # -> ValueError a = np.ones((4,3,2)) b = np.zeros((4,3,7)) np.concatenate([a,b], axis=2).shape # -> (4,3,9) -
-
Transpose
-
Matrix transpose
usage :
a.Te.g.
a = np.arange(6).reshape((3, 2)) b = a.T print(b.shape) # -> (2, 3) -
Tensor transpose
usage :
np.transpose(a, axes)- axes : 전체 axis 갯수의 tuple or list of ints 로, 원하는 순서의 axis 들의 나열
e.g.
a = np.arange(24).reshape((4, 3, 2)) b = np.transpose(a, [0, 2, 1]) print(b.shape) # -> (4, 2, 3) c = np.transpose(a, [1, 0, 2]) print(c.shape) # -> (3, 4, 2)
-
6. Broadcasting
Broadcasting : 두 배열이 다른 shape를 가지더라도 두 배열의 shape가 조건을 만족한다면, 둘 중 더 작은 dimension이 더 큰 dimension을 가지도록 만들어서 사칙연산이 가능하도록 하는 것을 말한다.
- 조건 : 동일한 dimension이거나 1이어야 한다.
https://numpy.org/doc/stable/user/basics.broadcasting.html
e.g.
# Vector and scalar
a = np.arange(3)
b = 2.
print(a+b) # -> [2. 3. 4.]
print(a-b) # -> [-2. -1. 0.]
print(a*b) # -> [0. 2. 4.]
print(a/b) # -> [0. 0.5 1. ]
# Matrix and vector
a = np.arange(6).reshape((3, 2))
b = np.arange(2).reshape((1, 2))
print((a+b).shape) # -> (3, 2)
# Tensor and matrix
a = np.arange(12).reshape((2,3,2))
b = np.arange(6).reshape((3,2))
print((a+b).shape) # -> (2, 3, 2)
print(a + b[None,:]) # -> (2, 3, 2)Quiz : Fill the function foo()
import numpy as np
def sigmoid(x):
return 1./(1. + np.exp(-x))
def foo(M, W):
# Define a function that, given M of shape (m,n) and W of shape (4n, n), executes the following:
# - Take the first half rows of M
# - Take the second half rows of M
# - Take the odd-numbered rows of M
# - Take the even-numbered rows of M
# - Append them horizontally in the listed order so that you obtain a matrix X of shape (?, 4n)
# - Linearly transform X with W so that you obtain a matrix Y of shape (?, ?)
# - Put Y through the sigmoid function
# - Obtain the sum of the row-wise mean
W = np.arange(16).reshape(8,2).astype('float') / 10.
M = (np.arange(20).reshape((10,2)).astype('float') - 10.) / 10.
foo(M, W)Answer
import numpy as np
def sigmoid(x):
return 1./(1. + np.exp(-x))
def foo(M, W):
(row, col) = M.shape
first_half_rows = M[:row//2]
second_half_rows = M[row//2:]
odd_num_rows = M[1::2]
even_num_rows = M[0::2]
X = np.hstack([first_half_rows, second_half_rows, odd_num_rows, even_num_rows])
# X = np.concatenate([first_half_rows, second_half_rows, odd_num_rows, even_num_rows], axis=1)
Y = np.dot(X, W)
sigmoid_Y = sigmoid(Y)
row_wise_mean = sigmoid_Y.mean(axis=0)
return np.sum(row_wise_mean)
W = np.arange(16).reshape(8,2).astype('float') / 10.
M = (np.arange(20).reshape((10,2)).astype('float') - 10.) / 10.
foo(M, W)👉🏼 관련 실습 코드 : https://github.com/Sunkyoung/PyTorch-Study/blob/main/PyTorch_Study_01_NumPy.ipynb