본문 바로가기

programming/python

[python 활용하기 #10] 행렬 연산 방법 (사칙연산, 행렬 곱, 내적, 외적)

[python 활용하기 #10] 행렬 연산 방법 (사칙연산, 행렬 곱, 내적, 외적)

 

안녕하세요. 심심한 코딩쟁이입니다.

 

오늘은 저번 포스팅에 이어 numpy를 통한 행렬 연산에 대한 내용을 살펴보겠습니다.

 

만약 numpy가 아직 설치되어있지 않으신 분들은 아래 글을 참고해 설치한 다음

 

[python 활용하기#9] 파이썬 numpy 설치하기

 

 

[python 활용하기#9] 파이썬 numpy 설치하기

[python 활용하기#9] 파이썬 numpy 설치하기 안녕하세요. 심심한 코딩쟁이입니다. 오늘은 행렬이나 다차원 배열의 연산을 쉽고 빠르게 처리하도록 지원해주는 라이브러리 numpy의 설치방법을 살펴보

symxsym.tistory.com

 

본문 내용을 따라와 주시면 감사하겠습니다.

 

시작합니다.

 

Numpy
NumPy 로고


덧셈

 

행렬의 덧셈을 numpy로 구현해 봅시다.

 

plus
덧셈

 

덧셈을 진행할 행렬들의 정보입니다.

 

import numpy as np

a = np.array([[1, 2], [3, 4]])
b = np.array([[9, 8], [7, 6]])

print(a + b)

####################
# 출력 결과
####################
[[10 10] 
 [10 10]]

 

같은 Shape을 가지고있는 행렬 간의 합이었습니다. 

 

그렇다면 다른 Shape을 가진 행렬간의 합은 어떻게 될지 살펴보시죠.

 

import numpy as np

a = np.array([[1, 2], [3, 4]])
b = np.array([5, 5])

print(a + b)
####################
# 출력 결과
####################
[[6 7]
 [8 9]]
 
a = np.array([[1, 2], [3, 4]])
b = np.array([[5], [5]])

print(a + b)
####################
# 출력 결과
####################
[[6 7]
 [8 9]]

 

위 코드를 살펴보면 행렬의 형태가 아래 그림과 같이 구성된 행렬들의 덧셈을 의미합니다.

 

plus
다른 형태를 가진 행렬들의 덧셈

 

형태가 다른 행렬간의 연산이 가능하도록 해주는 numpy의 기능을 브로드캐스팅 이라고 합니다.

 

아래 이미지는 numpy 공식 홈페이지에서 가져온 브로드캐스팅의 예시 이미지입니다.

 

broadcasting
broadcasting 예시

 

broadcasting
broadcasting 예시

 

broadcasting
broadcasting 예시

 

형태가 다르더라도 연산이 가능하게 해주는 기능이 있다는 것을 알아두시면 좋겠습니다.

 

브로드캐스팅은 덧셈, 뺄셈, 곱셈, 나눗셈, 나머지, 제곱 모두 가능합니다.


뺄셈

 

행렬의 덧셈을 numpy로 구현해 봅시다.

 

minus
뺄셈

 

뺄셈을 진행할 행렬들의 정보입니다.

 

import numpy as np

a = np.array([[1, 2], [3, 4]])
b = np.array([[9, 8], [7, 6]])

print(a - b)
#############
# 출력 결과
#############
[[-8 -6]
 [-4 -2]]
 
 a = np.array([[1, 2], [3, 4]])
b = 2

print(a - b)
#############
# 출력 결과
#############
[[-1 0]
 [1 2]]

 

같은 위치에 있는 수끼리 뺄셈이 이루어진 것을 볼 수 있습니다.

 

스칼라값을 행렬의 뺄셈에 사용하면 모든 요소들에 스칼라값을 뺀 결과를 반환해 줍니다.

 

이는 다른 연산에도 모두 적용됩니다.


나눗셈

 

이번엔 같은 형태의 행렬 간의 나눗셈을 살펴보겠습니다.

 

division
나눗셈

 

import numpy as np

a = np.array([[2, 8], [6, 2]])
b = np.array([[1, 4], [3, 2]])

print(a / b)
############
# 출력 결과
############
[[2. 2.]
 [2. 1.]]

 

역시 같은 위치에 있는 수끼리 나눗셈이 이루어진 것을 볼 수 있습니다.


곱셈

 

같은 형태를 가진 두 행렬간의 단순 곱셈을 살펴보겠습니다.

 

multiply
단순 곱셈

 

import numpy as np

a = np.array([[1, 3], [5, 7]])
b = np.array([[2, 2], [4, 4]])

print(a * b)
##############
# 출력 결과
##############
[[ 2  6]
 [20 28]]

 

위에서 살펴본 것과 마찬가지로 같은 자리에 위치한 숫자끼리 곱셈이 이루어진 것이 확인됩니다.

 

하지만 우리는 다른 형태의 행렬 간의 곱을 알고 있습니다. 바로 선형대수에서의 행렬 곱과 벡터의 곱인 내적입니다.

 

이것들도 numpy로 구현이 가능합니다.


행렬 곱

 

행렬 곱을 수행하려면 조건이 있습니다.

 

곱하려면 행렬의 행과 열의 개수를 보면 (2 , 3) , (3, 4) 이런 식으로 앞 행렬의 열과 뒷 행렬의 행의 개수가 같아야

 

연산이 가능해집니다.

 

multiply
행렬 곱

 

실제로는 행렬 곱의 표기를 x로 하지만 numpy에서 @로 표현하기 때문에 이미지에도 @로 표기하였습니다.

 

코드로 구현해 봅시다.

 

import numpy as np

a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[1, 1], [2, 2], [3, 3]])

print(a.shape, b.shape)
print("행렬 곱 가능")
print(a @ b)

#####################
# 출력 결과
#####################
(2, 3) (3, 2)
행렬 곱 가능
[[14 14]
 [32 32]]

 

결과값이 왜 저렇게 나오는지 이해가 잘 안 된다면 아래 그림을 참고해 주세요.

 

result
행렬 곱의 값


내적

 

벡터 간의 곱을 내적이라고 하며 1차원 벡터간의 내적은 결과값으로 스칼라값 하나가 나오게 됩니다.

 

차원이 올라가면 여러 개의 값이 나오겠죠?

 

내적도 행렬의 곱과 같이 행과 열 조건이 일치해야 계산이 가능합니다.

 

numpy에서는 .dot()을 사용해 구현할 수 있습니다.

 

import numpy as np

a = np.array([1, 0, 2])
b = np.array([[2], [2], [4]])

print(a.dot(b))
#################
# 출력 결과
#################
[10]

a = np.array([1, 0, 2])
b = np.array([[2, 1], [2, 2], [4, 3]])

print(a.dot(b))
#################
# 출력 결과
#################
[10  7]

외적

 

참고로 numpy에서 벡터의 외적도 다룰 수 있는데 벡터 a와 b에 대한 외적을 구하려면

 

numpy.cross(a, b)를 통해 계산이 가능합니다. 코드는 생략하도록 하겠습니다.


여기까지 numpy를 통한 행렬의 다양한 연산방법에 대해 알아보았습니다.

 

혹시 행렬의 곱과 내적의 계산 방법이 같아 보인다고 생각하셨다면 차원을 늘려보시기 바랍니다.

 

전혀 다른 결과가 나올 거예요.

 

수학적인 이론을 설명하기엔 주제를 벗어나는 내용이 될 것 같아 간단하게 적어보았습니다.

 

궁금하신 점이나 도움이 필요하신 분들은 댓글을 남겨주세요.

 

감사합니다.

반응형