본문 바로가기
[Library] - Numpy/Quick Start

# 4. Basic Operations

by Bebsae 2022. 2. 19.

이번 포스트에서는 기본적인 넘파이 연산들에 대해 다뤄볼 것이다.

 

a = np.array([20, 30, 40, 50])
b = np.arange(4)
c = a - b

# 1 Operation
print(b)
>>>
array([0, 1, 2, 3])

# 2 Operation
print(c)
>>>
array([20, 29, 38, 47])

# 3 Operation
print(b**2)
>>>
array([0, 1, 4, 9])

# 4 Operation
print(10 * np.sin(a))
>>>
array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])

# 5 Operation
print(a < 35)
>>>
array([ True,  True, False, False])

넘파이에서 산술 연산은 원소끼리(elementwise) 적용된다. 즉, 같은 차원에 존재하는 값들끼리 연산된다는 의미이다. 그리고, 연산의 결과는 새로운 배열이 생성되고 값이 채워지는 형태로 나타난다.

  • 2, 3, 4, 5 Operation을 보면 같은 shape을 가지고 있는 배열 a와 b가 elementwise 연산을 수행한 것이다. 
  • 4 Operation을 보면 np.sin(a)는 (4,) shape를 가지고 있는 배열인데 각각의 원소에 10을 곱한 것이다. (브로드 캐스팅, 이 부분은 추후 포스팅에서 더 자세히 다룰 예정)

 

A = np.array([[1, 1],
              [0, 1]])
B = np.array([[2, 0],
              [3, 4]])

# elementwise product
print(A * B)
>>>
array([[2, 0],
       [0, 4]])

# matrix product
print(A @ B)
>>>
array([[5, 4],
       [3, 4]])

# another matrix product
print(A.dot(B))
>>>
array([[5, 4],
       [3, 4]])

* 연산은 elementwise 곱으로 (Hadamard product) 행렬 A와 B사이의 같은 차원의 값들끼리 곱해졌다.  반면, 일반적인 행렬곱을 수행하려면 @ 연산자.dot() 메소드를 사용하면 된다.

 

import numpy as np

rg = np.random.default_rng(1) # create instance of default random number generator
a = np.ones((2, 3), dtype=int)
b = rg.random((2, 3))

print(a)
>>>
array([[1, 1, 1],
       [1, 1, 1]])
print(b)
>>>
array([[0.51182162, 0.9504637 , 0.14415961],
       [0.94864945, 0.31183145, 0.42332645]])

a *= 3
print(a)
>>>
array([[3, 3, 3],
       [3, 3, 3]])

b += a
print(b)
>>>
array([[3.51182162, 3.9504637 , 3.14415961],
       [3.94864945, 3.31183145, 3.42332645]])

a += b
>>>
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
numpy.core._exceptions.UFuncTypeError: Cannot cast ufunc 'add' output from dtype('float64') to dtype('int32') with casting rule 'same_kind'
  • np.random.defualt_rng(seed)는 랜덤으로 번호를 생성해주는 제너레이터이다.
  • b += a 연산의 경우에는 float64 데이터 타입의 행렬 b에 int32 데이터 타입의 행렬 a를 더하는 연산을 수행하므로 캐스팅 오류가 나지않는다. (행렬 a의 데이터 타입을 float64 데이터 타입으로 캐스팅 하는데에 문제가 없음.)
  • 반면, a += b 연산의 경우에는 int32 데이터 타입 행렬 a에 float64 데이터 타입의 행렬 b를 더하는 것이므로, float64 타입의 행렬 b를 int32 데이터 타입으로 캐스팅할 때 문제가 발생한다. (64비트를 32비트의 메모리에 할당할 때에 누수 현상이 발생)

 

import numpy as np

a = np.ones(3, dtype=np.int32)
b = np.linspace(0, np.pi, 3)

print(b)
>>>
array([0.        , 1.57079633, 3.14159265])

print(b.dtype)
>>>
dtype('float64')

print(b.dtype.name)
>>>
'float64'

c = a + b
print(c)
>>>
array([1.        , 2.57079633, 4.14159265])

d = np.exp(c * 1j)
print(d)
>>>
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
       -0.54030231-0.84147098j])
       
print(d.dtype.name)
>>>
'complex128'

print(type(d.dtype))
>>>
<class 'numpy.dtype'>
  • np.exp() 메소드를 사용하여 자연 상수를 밑으로 취할 수 있다.
  • 넘파이 배열에 dtype 필드를 호출하면 numpy.dtype 클래스 타입의 객체가 반환된다. 해당 객체는 name 프로퍼티를 사용하여 데이터 타입을 문자열로 얻을 수 있다.

 

rg = np.random.default_rng(1)
a = rg.random((2, 3))
print(a)
>>>
array([[0.51182162, 0.9504637 , 0.14415961],
       [0.94864945, 0.31183145, 0.42332645]])
       
print(a.sum())
>>>
3.290252281866131

print(a.min())
>>>
0.14415961271963373

print(a.max())
>>>
0.9504636963259353

랜덤 제너레이터 인스턴스 rg를 통해 (2, 3) shape의 난수 배열 a를 생성했다.

  • sum() : 모든 원소의 합
  • min() : 모든 원소에서 최소값
  • max() : 모든 원소에서 최대값

 

b = np.arange(12).reshape(3, 4)
print(b)
>>>
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

# sum of each column
print(b.sum(axis=0))    
>>>
array([12, 15, 18, 21])

# min of each row
print(b.min(axis=1))
>>>
array([0, 4, 8])

# cumulative sum along each row
print(b.cumsum(axis=1))
>>>
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])

 

  • 행렬 b의 shape은 (3, 4)이다. 여기서 axis=0은 첫 번째 차원인 3을, axis=1은 두 번째 차원인 4를 의미한다.
  • sum(axis=0)은 첫 번째 차원인 3행에 대한 합을 의미한다. 즉, 3개 행의 원소들을 합해야 한다는 의미이므로 세로로 원소를 합하면 된다. array([12, 15, 18, 21])를 보면, 12는 0 + 4 + 8 / 15는 1 + 5 + 9 ..
  • min(axis=1)은 두 번째 차원인 4열에 대한 최소값을 의미한다. 즉, 4개 열에서 최소값을 찾는 것이기 때문에 가로(행)로 최소값을 찾으면 된다. 각 행에서 최소값은 0, 4, 8이다.
  • cumsum(axis=1)은 두 번째 차원인 4열에 대한 누적합(accumulate sum)을 의미한다. 즉, 4개 열의 원소들을 누적해나가면 되는것이기 때문에 [0, 1, 3, 6]을 보면 0은 0 / 1은 0 + 1 / 3은 0 + 1 + 2 / 6은 0 + 1 + 2 + 3

 

참고

https://numpy.org/devdocs/user/quickstart.html

 

NumPy quickstart — NumPy v1.23.dev0 Manual

NumPy provides familiar mathematical functions such as sin, cos, and exp. In NumPy, these are called “universal functions” (ufunc). Within NumPy, these functions operate elementwise on an array, producing an array as output. See also all, any, apply_al

numpy.org

 

'[Library] - Numpy > Quick Start' 카테고리의 다른 글

# 5. Universal functions  (0) 2022.02.25
# 3. Printing Arrays  (0) 2022.02.19
# 1. Numpy Array Creation  (0) 2022.01.09
# 0. Numpy 기초  (0) 2022.01.07

댓글