새소식

반응형
Library/NumPy

[NumPy] 넘파이 다차원 배열 연산

  • -
반응형

넘파이 다차원 배열 연산


넘파이(Numpy)를 사용한 다차원 배열 연산은 다차원 배열(또는 행렬)에 대한 다양한 수학적, 통계적, 및 선형 대수 연산을 수행하는 것을 의미한다. 다차원 배열 연산은 데이터 분석, 과학 및 엔지니어링 응용 프로그램에서 매우 중요하며, 넘파이는 이러한 작업을 간편하게 수행할 수 있는 강력한 도구를 제공한다.
 

산술 연산

넘파이(Numpy)를 사용한 산술 연산은 다차원 배열(또는 행렬)에 대한 기본적인 수학적 연산을 포함한다. 다차원 배열의 각 요소에 대한 연산을 수행할 수 있다. 산술 연산을 수행할 때는 기본적으로 두 배열이 있을 때 같은 인덱스의 요소끼리 연산을 수행한다. 만약 두 배열의 길이가 다르면 산술 연산을 할 수 없기 때문에 두 길이가 다른 배열을 연산하려면 브로드캐스팅이라는 기능을 사용해야 한다. 다음은 넘파이를 사용한 산술 연산의 기본적인 사용법이다.
 

덧셈(Addition)

import numpy as np

arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

result = arr1 + arr2  # 결과: [5, 7, 9]

넘파이를 사용하여 두 배열 간의 요소별 덧셈을 위와 같이 수행할 수 있다.
 

뺄셈(Subtraction)

import numpy as np

arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

result = arr1 - arr2  # 결과: [-3, -3, -3]

두 배열 간의 요소별 뺄셈을 수행한다.
 

곱셈(Multiplication)

import numpy as np

arr = np.array([1, 2, 3])
scalar = 2

result = arr * scalar  # 결과: [2, 4, 6]

배열의 요소별 곱셈을 수행하며, 스칼라와의 곱셈도 가능하다.
 

나눗셈(Division)

import numpy as np

arr = np.array([4, 6, 8])
scalar = 2

result = arr / scalar  # 결과: [2.0, 3.0, 4.0]

배열의 요소별 나눗셈을 수행할 수 있으며, 스칼라로 나눌 수도 있다.
 

거듭제곱(Exponentiation)

import numpy as np

arr = np.array([2, 3, 4])

result = arr ** 2  # 결과: [4, 9, 16]

배열의 요소에 대한 거듭제곱을 수행할 수 있다.
 
이러한 넘파이 산술 연산을 활용하면 다차원 배열에서 수학적인 작업을 수행할 수 있으며, 데이터 처리 및 계산을 효율적으로 수행할 수 있다. 연산은 요소별로 이루어지므로 배열의 크기와 모양이 동일해야 한다.
 

브로드캐스팅(Broadcasting)

넘파이(Numpy)에서 브로드캐스팅(Broadcasting)은 서로 다른 모양의 배열 간에 산술 연산을 수행할 수 있도록 도와주는 매우 강력한 기능이다. 브로드캐스팅을 사용하면 모든 배열의 크기를 일치시키지 않고도 연산을 수행할 수 있으며, 코드를 간결하게 유지할 수 있다.
 
브로드캐스팅의 주요 특징은 아래와 같다.

  1. 크기 불일치 - 서로 다른 모양의 배열 간에 브로드캐스팅을 사용할 수 있다. 예를 들어, 스칼라(크기가 1인 배열)와 배열 간의 연산도 가능하다.
  2. 차원 불일치 - 배열의 차원이 다를 경우에도 브로드캐스팅을 사용할 수 있다. 브로드캐스팅을 통해 차원을 자동으로 맞출 수 있다.

브로드캐스팅의 규칙은 아래와 같다.

  1. 규칙 1 - 두 배열의 차원 수가 다를 경우, 차원 수가 더 큰 배열에 차원 수가 적은 배열의 차원을 추가하여 일치시킨다.
  2. 규칙 2 - 두 배열의 차원 크기가 다를 경우, 크기가 1인 차원을 가진 배열을 다른 배열과 동일한 크기로 늘린다.
  3. 규칙 3 - 두 배열의 차원 크기가 다르고 어느 한쪽에 1도 없을 경우, 브로드캐스팅은 실패한다.
import numpy as np

arr1 = np.array([1, 2, 3])
scalar = 2

# 스칼라와 배열의 곱셈 (브로드캐스팅)
result = arr1 * scalar  # [2, 4, 6]

스칼라(크기가 1인 배열)와 크기가 다른 배열의 연산을 수행하는 예제이다.
 
또한, 다차원 배열 간에 브로드캐스팅을 적용할 수 있으며, 두 배열을 일치시킬 때 규칙 1,2,3을 따른다. 브로드캐스팅은 넘파이의 강력한 기능 중 하나이며, 코드를 간결하게 작성하고 데이터 처리를 더 효율적으로 수행하는 데 도움이 된다.
 

import numpy as np

# 크기가 다른 두 배열 생성
arr1 = np.array([[1, 2], [3, 4]])  # 크기: (2, 2)
arr2 = np.array([10, 20])          # 크기: (2,)

# 크기가 다른 배열 간 브로드캐스팅 연산
result = arr1 + arr2

print(result)

 
arr1은 크기가 (2,2)인 2차원 배열이고, arr2는 크기가 (2,)인 1차원 배열이다. 브로드캐스팅을 통해 arr2가 자동으로 (2,2) 크기로 확장되어 arr1과 크기가 일치하도록 만든다. 그리고 각 요소별로 덧셈이 수행된다. arr2가 (2,2) 크기로 확장될 때 확장되는 요소는 기존 요소로 확장된다. 즉, arr2 = np.array([10,20], [10,20])과 같이 확장된다고 생각하면 된다.
 

[[11 22] 
 [13 24]]

실행 결과

 
 

행렬의 연산

넘파이(Numpy)를 사용한 행렬 연산은 다차원 배열(행렬)에 대한 다양한 선형 대수 연산을 수행하는 것을 의미한다. 넘파이를 사용하면 행렬과 관련된 다양한 작업을 효과적으로 수행할 수 있다. 다음은 넘파이를 사용한 행렬 연산에 대한 주요 내용이다.
 

행렬 생성

import numpy as np

# 2x2 크기의 행렬 생성
matrix = np.array([[1, 2], [3, 4]])

넘파이를 사용하여 행렬을 생성하는 예제이다, 위의 예제에서 행렬은 2차원 배열로 표현된다.
 

행렬 곱셈(Matrix Multiplication)

import numpy as np

matrix1 = np.array([[1, 2], [3, 4]])
matrix2 = np.array([[5, 6], [7, 8])

result = np.dot(matrix1, matrix2)

행렬 곱셈은 각 자리의 행과 열의 연산으로 생각하면 된다. 각 인덱스와 1대 1로 대치되는 matrix1의 행과 matrix2의 열과 연산한다고 생각하면 된다.
 
아래와 같이 연산되는 과정을 살펴보면 이해하기 수월할 것이다. 
 
matrix1 = ( [1,2] ,
                   [3,4] )
 
matrix2 = ( [5,6],
                   [7,8] )
 
(1 x 5) + (2 x 7) = 19
(1 x 6) + (2 x 8) = 22
(3 x 5) + (4 x 7) = 43
(3 x 6) + (4 x 8) = 50
 

[[19 22]
 [43 50]]

실행 결과

 
여기서 주의할 점은 matrix1의 행의 크기와 matrix2의 열의 크기가 같아야 연산을 할 수 있다. 예를 들어 matrix1은 (2,2), 그리고 matrix2 또한 (2,2)다. 빨간색과 파란색으로 표기한 부분, 두 배열의 행과 열의 크기가 같아야 한다는 의미이다.
 
(3,2) x (2,3)  → 연산 가능
(3,2) x (3,3) → 연산 불가능
 

행렬 곱셈 (2,3) x (3,2)

import numpy as np

# (2,3) 크기의 행렬 생성
matrix_a = np.array([[1, 2, 3], [4, 5, 6]])

# (3,2) 크기의 행렬 생성
matrix_b = np.array([[7, 8], [9, 10], [11, 12]])

# 행렬 곱셈 수행
result = np.dot(matrix_a, matrix_b)

# 또는 아래와 같이 "@" 연산자를 사용할 수도 있다.
# result = matrix_a @ matrix_b

print(result)

마찬가지로 의 연산으로 생각하면 이해하기 쉬울 것이다. 아래 연산과정을 한 번 살펴보자.

 

matrix_a = { [1,2,3],             matrix_b = { [7,8],

                    [4,5,6]         X                        [9,10],

                  }                                              [11,12] }    

 

(1 x 7) + (2 x 9) + (3 x 11) = 58

(1 x 8) + (2 x 10) + (3 x 12) = 64

(4 x 7) + (5 x 9) + (6 x 11) = 139

(4 x 8) + (5 x 10) + (6 x 12) = 154

[[ 58  64] 
 [139 154]]

실행 결과


 

전치 행렬(Transpose)

전치 행렬이란 주어진 행렬의 행과 열을 바꾼 행렬을 나타낸다. 전치 행렬은 원래 행렬의 행은 열로, 열은 행으로 변환된다. 이것은 행렬을 수학적으로 또는 프로그래밍적으로 다룰 때 유용한 연산 중 하나이다.

import numpy as np

matrix = np.array([[1, 2], [3, 4]])

transposed_matrix = matrix.T

행렬의 전치는 T 속성을 사용하여 수행한다. 아래의 실행 결과를 보면 행과 열의 자리가 바뀐 걸 확인할 수 있다.
 
matrix = ([1,2], 
               [3,4])
 
기존 matrix의 1열 (1,3)과 2열 (2,4)이 행으로 바뀌어 아래와 같이 변경된다고 생각하면 된다.
 
matrix = ([1,3],
               [2,4])
 

[[1 3]
 [2 4]]

실행 결과

 
 

행렬식(Determinant)

넘파이에서의 행렬식은 주어진 정방 행렬의 특성을 나타내는 수치 값으로, 주어진 행렬의 선형 변환에 대한 스케일링 요소나 확장 요소를 제공한다. 행렬식은 주어진 행렬이 특정 연산에 대해 어떻게 동작하는지, 선형 변환에서 부피를 어떻게 변화시키는지 등을 설명하는 중요한 수학적 개념이다.

import numpy as np

matrix = np.array([[1, 2], [3, 4]])

determinant = np.linalg.det(matrix)

위의 코드에서 matrix는 2 x 2 정방 행렬이고, np.linalg.det(matrix) 함수를 사용하여 이 행렬의 행렬식을 계산한다. 행렬식은 주어진 행렬이 역행렬을 가질 수 있는지, 행렬의 랭크(위상)를 확인하는 데 사용된다. 행렬식의 값이 0이면 역행렬이 존재하지 않고, 값이 0이 아니면 역행렬이 존재할 가능성이 있다. 또한 행렬식은 선형 대수학에서 선형 변환과 관련된 다양한 문제를 해결하는 데 중요한 역할을 한다.
 

-2.0000000000000004

실행 결과

 
 

역행렬(Inverse)

파이썬에서 역행렬은 주어진 행렬의 역수에 해당하는 행렬을 나타낸다. 역행렬은 정방 행렬(즉, 행과 열의 수가 같은 행렬)에 대해 정의되며, 행렬 곱셈을 통해 곱했을 때 항등 행렬(단위행렬)을 생성하는 행렬이다. 역행렬은 주어진 행렬을 역으로 취한 행렬로, 원래 행렬과 역행렬을 곱하면 항등 행렬이 된다.
 
파이썬에서 역행렬을 계산하려면 넘파이 또는 다른 선형 대수 라이브러리를 사용할 수 있다. 넘파이의 numpy.linalg.inv() 함수를 사용하여 역행렬을 계산할 수 있다.

import numpy as np

# 정방 행렬 생성
matrix = np.array([[2, 1],
                  [3, 4]])

# 역행렬 계산
inverse_matrix = np.linalg.inv(matrix)

# 결과 출력
print(inverse_matrix)

위의 예제에서 matrix 2 x 2 정방 행렬이고, np.linalg.inv(matrix) 함수를 사용하여 이 행렬의 역행렬을 계산한다. 역행렬은 선형 대수학에서 중요한 역할을 하며, 선형 방정식의 해를 찾는 데 사용되거나 다양한 수학적 및 공학적 문제를 해결하는 데 활용된다. 역행렬은 행렬의 특정 연산을 역으로 취한 결과로, 원래 행렬과 역행렬을 곱하면 항등 행렬이 되어야 한다.
 

[[ 0.8 -0.2] 
 [-0.6  0.4]]

실행 결과

 
 

Tensordot 연산

넘파이(Numpy)의 tensordot 함수는 다차원 배열(텐서)에 대한 텐서 점곱 연산을 수행하는 데 사용된다. 텐서 점복은 고차원 배열의 연산을 수행하는 데 유용한 도구이다. 이 연산은 다차원 배열의 내적과 유사하게 작동하지만, 다양한 축(axis)에 대한 점곱을 수행할 수 있다.
 
np.tensordot() 함수의 기본 구문은 아래와 같다.

np.tensordot(a, b, axes=axes)
  • a와 b는 텐서 점곱을 수행할 두 다차원 배열이다.
  • axes는 텐서 점곱을 어떻게 수행할지를 지정하는 매개변수로, 기본값은 2이다. axes는 두 개의 튜플로 나타내며, 각 튜플은 각 배열의 어떤 축을 점곱을 사용할 것인지를 지정한다.

예를 들어, 두 3차원 배열 a와 b에 대한 텐서 점곱을 수행하는 경우 다음과 같이 할 수 있다.

import numpy as np

a = np.random.random((2, 3, 4))
b = np.random.random((4, 3, 2))

result = np.tensordot(a, b, axes=([1, 2], [2, 1]))

위의 예제에서 axes 매개변수는 [1,2]와 [2,1]로 지정되었다. 이것은 첫 번째 배열 a에서 1번과 2번 축을, 두 번째 배열 b에서 2번과 1번 축을 사용하여 텐서 점곱을 수행한다는 의미이다. 결과 result는 2차원 배열이 된다.
 
텐서 점곱은 다차원 배열 연산에서 유용한 도구로 사용되며, 특히 신경망 및 딥러닝 모델에서 가중치 행렬과 입력 데이터를 처리하는 데 자주 사용된다. 이 연산을 통해 고차원 배열을 효과적으로 다룰 수 있다.
 
 

einsum 연산

NumPy에서 einsum은 텐서 조작 및 다차원 배열 연산을 수행하기 위한 강력한 도구 중 하나이다. einsum은 "Einstein summation"의 준말로, 다차원 배열의 내적, 축 합, 행렬 곱셈, 텐서 계산 등 다양한 연산을 수행하는 데 사용된다. enisum 함수를 사용하면 배열 조작이 효율적이고 간결하게 이루어질 수 있다.
 
einsum 함수는 아래와 같은 기본 구문을 가지고 있다.

numpy.einsum(subscripts, *operands, out=None, dtype=None, order='K', casting='safe', optimize=False)
  • subscripts - 텐서 연산을 지정하는 문자열이다. 이 문자열은 입력 및 출력 텐서 간의 연산을 정의한다.
  • operands - 연산에 참여하는 다차원 배열들을 나타내는 인수이다.
  • out(선택 사항) - 연산 결과를 저장할 배열이다.
  • dtype(선택 사항) - 연산 결과의 데이터 타입을 지정한다.
  • order(선택 사항) - 다차원 배열의 메모리 순서를 지정한다.
  • casting(선택 사항) - 데이터 형 변환 규칙을 지정한다.
  • optimize(선택 사항) - 연산을 최적화할지 여부를 나타내는 플래그이다.

subscripts 매개변수는 연산을 정의하는 데 사용되는 문자열로, 아래와 같은 방식으로 사용된다.

  • "abc, de -> f" - 두 입력 텐서 abc와 de를 받아 출력 텐서 f를 생성한다. 이것은 행렬 곱셈과 유사하다.
  • "a, a -> a" - 한 입력 텐서 a를 받아 출력 텐서 그대로 복사한다. 이것은 축 합계와 유사하다.
  • "ab, cd -> acbd" - 두 입력 텐서 ab와 cd를 받아 출력 텐서 acbd를 생성한다.

einsum은 매우 강력한 도구로, 다양한 고급 연산과 텐서 조작을 수행하는 데 사용된다. 이를 통해 다차원 배열의 차원 축소, 전치, 슬라이싱 및 행렬 곱셈과 같은 다양한 연산을 수행할 수 있다.
 
 
읽어주셔서 감사합니다.

728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.