Study/Python

[ Python ] 선형대수학 X 파이썬 | 벡터의 외적과 직교벡터 분해

L0521 2025. 3. 7. 23:28

군 내에서 아이패드, 사지방 컴퓨터를 이용하여 작성함. 본 내용은 자기개발 목적으로 책 '개발자를 위한 실전 선형대수학-한빛미디어', 유튜브 등을 참고하였음. 그래프는 Google Colab에서 작성함.


벡터의 외적


 외적열벡터행벡터를 사용하여 행렬을 만든다. 외적 행렬의 각 행은 행벡터 스칼라에 대응되는 열벡터 원소를 곱한 값이고, 각 열은 열벡터 스칼라에 대응되는 행벡터 원소를 곱한 값이다.
벡터의 외적은 내적의 차이가 있는데, 외적은 스칼라 대신 행렬을 생성한다. 또 외적은 두 벡터의 차원이 달라도 되지만 내적은 같아야 한다.

벡터의 외적 예시


벡터의 외적을 앞으로 다음과 같이 표기하겠다.

벡터의 외적 표기 방법

 
 외적은 브로드캐스팅과 비슷하지만 두 벡터를 곱하는 기법이므로 산술 연산을 벡터로 확장한 브로드캐스팅과는 다르다.
각각 열과 행 방향인 벡터가 존재할 때 np.outer(), np.cross() 두 함수를 통해 외적을 계산할 수 있다.


직교벡터 분해


 벡터와 행렬을 분해하면, 여러 조각으로 나뉘게 된다. 이를 통해 행렬을 분석하거나 변형하여 목적에 맞게 사용할 수 있다.

직교 투영

직교벡터 분해를 통해 직교 투영의 식을 유도할 수 있다.
표준 위치에 두 벡터 a, b가 있을 때, b벡터의 머리가 a벡터와 가장 가까운 점을 찾는다고 하자. b벡터를 a벡터에 투영한 거리가 최소가 되도록 한 지점을 βa라 할 때 b에서 βa까지의 선을 ba라고 정의할 수 있다.

위의 내용을 그림으로 표현한 것

ba와 βa는 직교하는 걸 알 수 있으므로 둘의 내적의 값은 0이 되어야 한다.
따라서 다음과 같은 식을 유도할 수 있다.

이와 같은 β를 직교 투영(orthographic projection 또는 정사영)이라고 한다.


직교벡터 분해

위에서 한 것처럼, 벡터를 분해하기 위해서는 목표벡터기준벡터를 설정해야 된다.(목표벡터를 두 개의 다른 벡터로 분해하려는 목적이다.)
이는 두 가지를 만족해야 된다.

  1. 분해된 두 벡터의 합이 목표벡터가 되어야 한다.
  2. 한 벡터는 기준벡터와 직교하고, 다른 벡터는 평행해야 된다.

목표벡터t, 기준벡터r이라 할 때, 주어진 상황은 다음과 같다.

따라서 직교 투영에서 구한 식을 이용하면 평행 성분을 찾을 수 있다.


직교 투영에서 구한 식은 스칼라 β값만 구했으나 이 식에서는 벡터 βr을 구할 수 있다. 이 벡터가 평행 성분이다.
수직 성분은 목표 벡터에서 평행 성분을 뺀 값으로 구할 수 있다.

 


파이썬으로 구현하기

 

np.cross()np.outer()의 차이

 np.cross()np.outer()는 외적을 계산하는 데 있어 차이점이 존재한다. 
벡터의 외적을 계산할 때는 np.cross()를 사용한다. 같이 외적이라고 불리는 np.outer()는 텐서곱이다.

# np.cross()을 이용한 벡터의 외적 예시
import numpy as np

Vec_a=np.array([1, 2, 3])
Vec_b=np.array([4, 5, 6])

cross_product = np.cross(Vec_a,Vec_b)
print(cross_product)


'''
>> [-3  6 -3]
'''

 

# np.outer()을 이용한 벡터의 외적(텐서곱) 예시
import numpy as np
 
Vec_a = np.array([1, 2, 3])
Vec_b = np.array([4, 5, 6])

outer_product= np.outer(Vec_a, Vec_b)
print(outer_product)


'''
>> [[ 4  5  6]
 [ 8 10 12]
 [12 15 18]]
'''

 
 

직교벡터 분해

 다음 코드는 두 난수 벡터 tr이 있을 때 두 성분의 합이 t이고 trt || r(수직 성분과 평행 성분)이 직교하는지 확인하는 것이다.

import numpy as np
import matplotlib.pyplot as plt

# 난수 벡터 t, r 생성
t = np.random.randn(2)
r = np.random.randn(2)

# 벡터 성분 분해
t_para = r * (np.dot(t,r) / np.dot(r,r))
t_perp = t - t_para

# 두 구성요소의 덧셈이 목표 벡터인지 확인
print(t)
print( t_para + t_perp )

# 직교임을 확인하기(내적의 값은 0)
print( np.dot(t_para,t_perp) )


# 그래프 틀 그리기
plt.figure(figsize=(6,6))

# 두 메인 벡터 그리기
plt.plot([0,t[0]],[0,t[1]],color='k',linewidth=3,label=r't')
plt.plot([0,r[0]],[0,r[1]],color=[.7,.7,.7],linewidth=3,label=r'r')

# 벡터의 두 구성요소 그리기
plt.plot([0,t_para[0]],[0,t_para[1]],'k--',linewidth=3,label=r't para')
plt.plot([0,t_perp[0]],[0,t_perp[1]],'k:',linewidth=3,label=r't perp')

plt.axis('equal')
plt.legend()
plt.savefig('Figure_01_08.png',dpi=300)
plt.show()


'''
>>[-1.19004149  0.34705056]
 [-1.19004149  0.34705056]
 0
 (아래 사진 참고)
'''