NumPy Master Class

Chapter1 ndarray: Notebook2 Making ndarray2

Shin's Lab 2020. 1. 8. 13:54
1_2_Making_ndarray2

NumPy Master Class

Chapter1 ndarray

Notebook2 Making ndarray2

저번 notebook1에서 ndarray를 초기화하는 방법을 배웠다면, 이번 notebook2에서는 프로그래밍 중간중간 기존 ndarray와 같은 shape을 가지는 ndarray를 만드는 방법에 대하여 배워본다.

1. np.ones_like()
2. np.zeros_like()
3. np.full_like()
4. np.empty_like()

위의 이름에서 알 수 있듯이, 저번 시간에 배웠던 np.ones, np.zeros, np.full, np.empty 뒤에 _like만 붙여준 함수들이다. 이 like함수들은 기존에 만들어져있던 ndarray와 같은 shape, 그리고 같은 dtype의 ndarray를 만들어주는 함수들이다.

따라서 argument는 기존에 만들어져있는 ndarray 하나면 충분하다.

(dtype은 뒤에 배우도록 하므로 새로 만들어진 ndarray가 전의 ndarray와 같은 dtype을 가지는 것만 확인하면 충분하다.)

In [2]:
import numpy as np
In [4]:
test_np = np.array([[1, 2], [3, 4], [5, 6]])
print("test_np:", test_np)
print("test_np.shape:", test_np.shape)
print("test_np.dtype:", test_np.dtype)
test_np: [[1 2]
 [3 4]
 [5 6]]
test_np.shape: (3, 2)
test_np.dtype: int64

위에서 테스트를 위한 test_np를 만들었다. 이 test_np는 3X2 matrix이며 int64라는 data type을 가지고 있는 것을 확인할 수 있다.


np.ones_like()

numpy.ones_like(a, dtype=None, order='K', subok=True, shape=None)

In [8]:
ones = np.ones_like(test_np)
print("ones:", ones)
print("ones.shape:", ones.shape)
print("ones.dtype:", ones.dtype)
ones: [[1 1]
 [1 1]
 [1 1]]
ones.shape: (3, 2)
ones.dtype: int64

위에서 확인할 수 있듯이, 1로 모두 채워져있는 ndarray가 만들어졌고, shape과 dtype이 동일함을 알 수 있다.


np.zeros_like()

numpy.zeros_like(a, dtype=None, order='K', subok=True, shape=None)

In [9]:
zeros = np.zeros_like(test_np)
print("zeros:", zeros)
print("zeros.shape:", zeros.shape)
print("zeros.dtype:", zeros.dtype)
zeros: [[0 0]
 [0 0]
 [0 0]]
zeros.shape: (3, 2)
zeros.dtype: int64

np.full_like()

numpy.full_like(a, fill_value, dtype=None, order='K', subok=True, shape=None)

위에서 말했듯이 _like() 함수들은 같은 shape, 같은 dtype의 ndarray를 만들어주는 역할을 한다.

그리고 zeros(), ones()와 다르게 full()는 shape 외에 fill_value를 넣어줘야 했다.

마찬가지로 full_like() 함수도 같은 shape, 같은 dtype을 만들어주면서 어떤 값을 넣어줘야 하는지에 대한 argument로 fill_value를 넣어줘야 한다.

In [7]:
full = np.full_like(test_np, fill_value = 10)
print("full:", full)
print("full.shape:", full.shape)
print("full.dtype:", full.dtype)
full: [[10 10]
 [10 10]
 [10 10]]
full.shape: (3, 2)
full.dtype: int64

np.empty_like()

numpy.empty_like(prototype, dtype=None, order='K', subok=True, shape=None)

In [10]:
empty = np.empty_like(test_np)

print("test_np:", test_np, '\n')
print("empty:", empty)
print("empty.shape:", empty.shape)
print("empty.dtype:", empty.dtype)
test_np: [[1 2]
 [3 4]
 [5 6]] 

empty: [[10 10]
 [10 10]
 [10 10]]
empty.shape: (3, 2)
empty.dtype: int64

위에서 볼 수 있듯이, empty는 memory만 할당해주기 때문에 새로 만들어진 ndarray의 memory에 전에 들어있던 값들이 나오는 것을 확인할 수 있다.

이상으로 4가지의 _like()함수들을 알아봤다. 이 함수들은 프로그래밍 초기 단계에서 사용되는 경우보단 프로그래밍 중간중간 연산을 할 때 많이 사용된다.

특정 ndarray에 모두 10을 더해주고 싶은 상황이라고 가정해보자. 그러면 뒤에 배울 broadcating을 이용하지 않는다면 다음과 같이 연산을 할 수 있다.

In [13]:
test_np = np.array([[1, 2], [3, 4]])

test_H, test_W = test_np.shape
test_dtype = test_np.dtype

added_np = np.full(shape = (test_H, test_W), dtype = test_dtype, fill_value = 10)
result_np = test_np + added_np

print("test_np:", test_np)
print("added_np:", added_np)
print("result_np:", result_np)
test_np: [[1 2]
 [3 4]]
added_np: [[10 10]
 [10 10]]
result_np: [[11 12]
 [13 14]]

즉, test_np의 shape, dtype을 먼저 찾고, 이를 통해 full() 함수를 이용하여 같은 shape, dtype을 가지는 ndarray를 만들어 더할 수 있다.

하지만 치명적인 문제 중 하나는 유지-보수가 힘들다는 것이다.

만약 test_np가 1차원이라도 늘어난다면 test_H, test_W 만으로는 제대로 작동하지 않는다. 따라서 뒤따라 오는 코드를 수정해줘야 하는 번거로움이 있다.

우리가 _like() 함수를 사용한다면 다음과 같이 간단해질 수 있다.

In [15]:
test_np = np.array([[1, 2], [3, 4]])

added_np = np.full_like(test_np, fill_value = 10)
result_np = test_np + added_np

print("test_np:", test_np)
print("added_np:", added_np)
print("result_np:", result_np)
test_np: [[1 2]
 [3 4]]
added_np: [[10 10]
 [10 10]]
result_np: [[11 12]
 [13 14]]