파이썬・ML/numpy

넘파이 배열의 원소별 연산 이해하기(Element-wise operation)

truezero 2023. 7. 27. 18:00

이번 포스팅에서는 넘파이 배열의 연산 방식에 대해 알아보도록 하겠습니다.

Element-wise 연산?

arr1 = np.random.randint(-5, 5, (5, ))
print(arr1)  # [ 1 -1 -3  3  2]

arr2 = np.random.randint(-5, 5, (5, ))
print(arr2)  # [ 3  4 -5  4 -3]

print(arr1 + arr2)
# [ 4  3 -8  7 -1]

기본적으로 넘파이 배열은 모두 원소별 연산을 수행합니다.

원소별로 연산한다는 것의 의미는 각 배열의 동일한 인덱스에 위치한 값들끼리 계산한다는 말입니다.

단, 연산하는 배열들의 shape은 동일해야 합니다.

 

M = np.random.randint(1, 5, (2, 3))
print(M)
# [[2 4 1]
#  [4 4 2]]

N = np.random.randint(1, 5, (2, 3))
print(N)
# [[1 3 4]
#  [1 2 4]]

print(M + N)
# [[3 7 5]
#  [5 6 6]]

print(M - N)
# [[ 1  1 -3]
#  [ 3  2 -2]]

print(M >= N)
# [[ True  True False]
#  [ True  True False]]

2차원 배열의 원소별 연산 예제입니다.

- 산술 연산자

a = np.random.randint(1, 5, (5, ))
print(a)
# [4 3 2 1 4]

b = np.random.randint(1, 5, (5, ))
print(b)
# [3 1 4 1 4]

print('a + b = {}'.format(a + b))
# a + b = [7 4 6 2 8]
print('a - b = {}'.format(a - b))
# a - b = [ 1  2 -2  0  0]
print('a * b = {}'.format(a * b))
# a * b = [12  3  8  1 16]
print('a / b = {}'.format(a / b))
# a / b = [1.33333333 3.   0.5   1.   1.]
print('a % b = {}'.format(a % b))
# a % b = [1 0 2 0 0]
print('a // b = {}'.format(a // b))
# a // b = [1 3 0 1 1]
print('a ** b = {}'.format(a ** b))
# a ** b = [64   3  16   1 256]

넘파이 배열은 사칙연산 뿐만 아니라 몫, 나머지, 지수 연산도 수행 가능합니다.

- 비교 연산자

a = np.random.randint(-5, 5, (5, ))
print(a)  # [-5 -1  0 -1  4]

b = np.random.randint(-5, 5, (5, ))
print(b)  # [ 3 -4  2  1 -5]

print('a > b: {}'.format(a > b))
# a > b: [False  True False False  True]
print('a >= b: {}'.format(a > b))
# a >= b: [False  True False False  True]
print('a < b: {}'.format(a < b))
# a < b: [ True False  True  True False]
print('a <= b: {}'.format(a <= b))
# a <= b: [ True False  True  True False]
print('a == b: {}'.format(a == b))
# a == b: [False False False False False]
print('a != b: {}'.format(a != b))
# a != b: [ True  True  True  True  True]

비교 연산자를 사용해서 넘파이 배열에 대한 연산을 수행하는 경우에는 불리언 배열을 리턴합니다.

리턴 받은 불리언 배열을 사용해서 배열을 마스킹할 수 있습니다.

- 마스킹

arr = np.arange(5)
print(arr)
# [0 1 2 3 4]

mask = np.array([0, 1, 0, 1, 0])
print(arr * mask)
# [0 1 0 3 0]

마스킹은 필터링(filtering)을 의미합니다.

0, 1로 구성된 배열을 사용해서 배열의 특정 부분만 남기고 나머지 부분은 모두 0으로 처리합니다.

 

matrix = np.arange(1, 5).reshape((2, 2))
print(matrix)
# [[1 2]
#  [3 4]]

mask = np.array([[0, 0], [1, 0]])
print(matrix * mask)
# [[0 0]
#  [3 0]]

2차원 배열에 대해 마스킹 연산을 수행하는 예제입니다.

마치며

이상으로 넘파이 배열의 원소별 연산에 대한 정리를 마치도록 하겠습니다.

원소별 연산 방식(Element-wise operation)은 브로드캐스팅 개념을 이해하기 위한 필수 개념입니다.

다음 포스팅에서는 대망의 브로드캐스팅에 대해 알아보도록 하겠습니다.