최근 정부를 비롯해 기업에서도 많은 관심을 기울이고 있는 것이 바로 4차 산업혁명이다. 이 4차 산업혁명을 의미하는 키워드들을 간략히 언급하자면 다음의 것들이 있다. 


인공지능(Artificial Intelligence), IoT(Internet of Things), 3D-Printer, 로봇(Robotics), AR(Augmented Reality), VR(Virtual Reality), 빅데이터(Big-Data), 웨어러블로봇(Wearable Robotics), 자율주행차(Autonomous Driving Car), 드론(Drone), ... 



관련 전공자가 아니더라도 한 번쯤은 들어봤던 단어들일 것이다. 

위에 나열한 키워드들을 보면 공통적으로 요구되는 기술이 있다. 바로 소프트웨어(Software)기술이다. 위에 나열된 그 어떠한 것도 소프트웨어 없이는 구현될 수 없다. 정부에서도 이러한 소프트웨어의 중요성을 인식하고 2018년부터 관련 교육을 의무화 한다고 공표하였다. 그 만큼 중요하다. 


그렇다면 전 세계적으로 어떠한 소프트웨어들이 사용되고 있을까? 또한 어떠한 소프트웨어들이 존재하는 것일까? 소프트웨어 관심을 가진 사람이라면 한 번쯤 이러한 생각을 해본 적이 있을 것이다. 이번 포스팅에서는 세상에 존재하는 수 많은 프로그래밍 언어들이 얼마나 인기가 있고 널리 사용되는지에 대해 알아보고자 한다. 




1. TIOBE index 



Fig. 1 TIOBE Ranking. 검색엔진의 쿼리와 웹페이지 정보를 기반으로 Ranking을 정한다. (2017년 4월 기준)



전 세계 사람들이 가장 많이 사용하는 프로그래밍 언어는 무엇일까? 이와 관련된 정보를 제공해주는 회사가 네덜란드에 위치한 TIOBE(https://www.tiobe.com/)이다. 이 회사에서 제공하는 서비스 중 한 가지는 프로그래밍 언어에 대한 Ranking을 제공한다. Google, Yahoo, Baidu, Wikipedia, Youtube 외에 사람들에게 널리 사용되는 검색엔진들의 검색 쿼리(queries)와 관련 웹페이지들을 수집하여 쿼리와 웹페이지에 포함된 각 프로그래밍 언어의 단어 숫자들의 통계치를 기반으로 순위를 매기는 방식이다. 이 index는 한 달에 한 번 업데이트 되며, 무료로 볼 수 있다. 그러나 긴 기간동안의 특정 통계치는 팔기도한다.  


주의해야 할 것은 이들이 제공하는 Ranking은 최고의 프로그래밍 언어(Best Programming Language)에 대한 Ranking이 아니며, 가장 많은 수의 line이 작성된 언어도 아니다. 단지 인터넷에서 많이 회자되는 언어를 기반으로 전세계에서 가장 많이 사용되는 프로그래밍 언어를 추정한 추정치이다. 프로그래밍 관련 순위를 보려면 아래 링크로 접속하면 된다. 


https://www.tiobe.com/tiobe-index//


2017년 4월 기준으로 Java가 1위이며, C와 C++, C#, python등이 뒤를 잇는다. 순위에 따른 점유율(Ratings)을 제공하며, 그간의 순위 변동을 그래프로 볼 수도 있다. 




2. PYPL index 



Fig. 2 PYPL Ranking. Google trends데이터를 기반으로 Ranking이 정해진다. 프로그래밍 언어 뿐만 아니라 통합개발환경(IDE), DB언어 등에 대한 Ranking도 제공한다. (2017년 4월 기준)



PYPL(PopularitY of Programming Language) index는 Google trends의 통계데이터를 기반으로하며, 사용자들이 각 프로그래밍 언어의 튜토리얼(tutorial)을 얼마나 검색하는지에 대한 통계치를 기반으로 Ranking을 매긴다. 프로그래밍 언어 뿐만 아니라 visual studio 등과 같은 통합개발환경 IDE(Integrated Development Environment), ODE(Online Integrated Development Environment), 그리고 SQL과 같은 DB언어에 대한 Ranking도 보여준다. 아래 링크에서 순위를 볼 수 있다. 


http://pypl.github.io/PYPL.html


이들이 주장하는 바로는 TIOBE index는 단순히 웹페이지에 포함된 프로그래밍 언어 단어들을 기반으로 추정치를 산출하기 때문에 정확하지 않다고 한다. 단순히 웹페이지나 쿼리에 프로그래밍 언어와 관련된 단어가 존재한다고 해서 그것을 사람들이 사용하거나 공부한다고는 할 수 없으며, 관련 튜토리얼을 검색한 사람이 적극적인 유저라고 할 수 있기 때문에 자신들이 더 정확하다고 주장한다. 뭐 어느 정도는 일리있는 것 같긴 하다. 2017년 4월을 기준으로 1위는 Java로 TIOBE의 Ranking과 같으며, python, php, C#, Javascript가 뒤따른다. 순위가 약간 다르다. 




3. RedMonk index 



Fig. 3 RedMonk Ranking. Github와 StackOverflow의 자료를 기반으로 Ranking을 정한다. (2017년 4월 기준)



RedMonk의 프로그래밍 언어 Ranking은 Github와 Stackoverflow자료를 기반으로 제공된다. Github에 각 프로그래밍 언어로 작성된 소스코드들의 Pull Request(소스코드가 변경되었다고 Github와 다른 사용자들에게 알리는 행위)의 숫자를 수집하고, Stack Overflow사이트에서 주고 받는 질문과 답변, 그리고 태그 정보들을 수집하여 이 둘을 조합하여 순위를 매기는 방식이다. TIOBE나 PYPL index와 달리 실제 소스코드에 대한 지표를 고려한다는 점에서 차별화 되어있다. RedMonk의 Ranking은 아래의 링크에서 확인할 수 있다. 


http://redmonk.com/sogrady/category/programming-languages/





4. 마치며 


위에서 언급한 사이트 이외에도 다양한 Ranking사이트들이 존재한다. 그러나 가장 널리 알려진 것은 위의 세개 정도이며, 나머지 Ranking index에 관한 내용은 여기에서 간략히 볼 수 있다. 

사실 어떤 지표가 더 낫다, 더 정확하다고 자신있게 얘기할 순 없다. 각기 다른 기준의 지표를 사용하고 있으며 각자가 주장하는 합리적 근거가 있기 때문에 그저 개인의 판단에 맡기는 수밖에 없을 것 같다. 세부적으로는 순위에 약간씩 차이가 있긴 하지만, 높은 순위에 Rank되는 언어들은 비슷한 양상을 보인다. Java계열 언어는 거의 독보적 1위를 차지하고 있으며 python과 C계열 언어, PHP등이 높은 순위에 올라와있다. 약간씩 다른 기준과 지표들을 활용하고 있지만, 결과적으로는 비슷한 양상을 보이기 때문에 너무 어느 한 쪽을 맹신하거나 혹은 불신하거나 하지는 않아도 될 것 같다. 개인적으로는 튜토리얼 검색 기반의 PYPL방식이 가장 좋아보이기는 한다. 그리고 IDE나 DB언어의 Ranking을 함께 제공해주는 것도 가장 마음에 든다. 어디까지나 개인적인 의견일 뿐이지만.


사실 필자도 이렇게나 많은 언어가 존재하는지는 몰랐다. Java가 너무 우위를 점하고 있어서 Java를 배울까 하는 생각을 아주 잠깐 하기도 했었지만, 어떤 언어를 다루는지는 사실 그렇게 중요하지 않을 수 있다. 중요한건 문제 파악 능력과 해결 능력이 아닐까. 




참고로 프로그래밍 입문자나 새로운 프로그래밍 언어를 배워보고자 하는 사람이 있다면 "Which Programming Language should I learn first"을 참고하는 것도 괜찮을 것 같다. 


지난 강의 Lecture 17-(1)에 이어 직교행렬과 그람-슈미트 과정 두 번째 강의다. 반드시 이전 강의에서 직교행렬(orthogonal matrix)을 공부하고 오기를 추천한다. 이제 그람-슈미트 과정(Gram-Schmidt Process)에 대해 공부해보도록 하자. 

 

 

4. 그람-슈미트 과정(Gram-Schmidt Process)

 

지난 강의의 마지막 부분에서 잠깐 언급했듯이, 그람-슈미트 과정(Gram-Schmidt Process)은 어떤 임의의 행렬 A의 column vector를 orthonormal column들로 바꾸는 것이다. 즉 행렬 A를 정규직교벡터(orthonormal vector)들로 이루어진 직교 행렬(orthogonal matrix) Q로 만드는 것이다. 이때 중요한 조건은 A의 column vector들이 독립(independent)이어야 한다. 아래 그림을 보자. 

 

 

Fig. 1 두 개의 독립(independent)인 벡터

 

 

Fig. 1은 두 개의 독립(independent)인 벡터를 나타낸다. 두 벡터 a와 b를 임의의 차원의 공간에서 2차원을 정의하는 기저벡터라고 하자. a와 b는 독립이기 때문에 분명 선형조합(Linear combination)을 통해 2차원 공간의 모든 벡터를 나타낼 수는 있다. 그러나 보다 효과적인 연산, 간단한 연산을 위해 이들을 똑같은 공간을 정의하는 정규직교벡터(orthonormal vector)로 만들고 싶은 것이다. 그람-슈미트 과정은 이렇게 독립인 벡터들을 정규직교벡터로 만들어준다. 

 

그람-슈미트 과정의 아이디어는 다음과 같다. 먼저 맨 처음 벡터인 a는 그대로 두고 시작한다. 이 a를 기준으로 a에 직교(orthogonal)한 벡터를 만들어낸다. 이를 각각 q1, q2라고 하자. 즉 a->q1, b->q2로 만드는 것이다. 여기까지 그람(Gram)의 아이디어다. 다음으로 할 일은 직교 벡터인 q1, q2를 정규직교벡터(orthonormal vector)로 만드는 것이다. 이는 q1과 q2를 각각 자신의 크기로 나누어주면 된다. 이것이 슈미트(schmidt)의 아이디어다. 지금까지의 과정을 정리하면 아래와 같다. 

 

Fig. 2 그람-슈미트(Gram-Schmidt)의 과정

 

 

- (1) Making Orthogonal Vectors (by Gram)

 

이제 Fig. 1의 두 벡터 a와 b를 가지고 그람-슈미트 과정을 수행해보자. 먼저 벡터 a는 그대로 q1이 된다. 마치 초기값과 같은 것이다. a->q1으로 변하는 과정은 전혀 문제가 없다. 문제는 b->q2의 과정이다. 왜냐하면 b는 a에 직교하지 않기 때문이다. 우리가 하고자 하는 것은 a와 독립이지만 직교는 아닌 벡터 b에서 출발하여 a와 직교인 벡터 q2를 찾는 것이다. q2를 어떻게 만들 수 있을까? 바로 Lecture 15에서 배웠던 투영(Projection)을 이용하는 것이다. 아래 그림을 보자. 

 

 

Fig. 3 투영을 이용한 직교 벡터 계산 방법

 

 

첫 번째 벡터인 빨간색 a는 그대로 q1이 된다. 그다음 두 번째 벡터 b를 a에 투영시켜서 p를 만드는데, 이때 error벡터인 e를 만들어낼 수 있다. 즉 b를 a에 투영시킬때, a에서 b에 가장 가까운 지점은 b와 연결되면서 a에 수직한 지점이다. 투영의 정의에 의해서 b와 연결되는 a에 수직한 지점으로 투영이 되어 벡터 p가 생성되고, 결과적으로 b에서 p를 빼면 e=b-p 를 계산할 수 있다. 이때의 e는 a와 수직(perpendicular)한 벡터가 되고 e가 곧 q2가 된다. 결국 투영(projection)을 이용하여 a=q1에 수직한 벡터 e=q2를 만들어낼 수 있다

 

투영 파트에서는 구하고자 하는 벡터가 p였고 e는 그저 버려지는 벡터였는데, 이번엔 반대로 p가 버려지고 e를 취하게 되었다. 투영에 관한 자세한 사항은 위에 링크를 걸어놓은 Lecture 15를 참고바란다. 

 

 

그렇다면 q2에 대한 실제 식은 어떻게 될까? 아직 투영 행렬 P를 모르는 상태이고, 주어진 것은 벡터 b와 벡터 a=q1이다. e=b-p에서 p에 대한 식만 정리하면 된다. 식은 아래와 같다. 

 

 

뭔가 익숙한 식일 것이다. Lecture 15(이해가 안가면 꼭 먼저 공부하고 오자)에서 벡터를 이용하여 투영 벡터를 구할 때 보던 식이다. p=xa에서 분수 부분이 바로 x에 해당한다. 현재 q1은 원래의 a와 같다. 이렇게 하여 q2를 구하였다. 결과적으로 q1과 q2는 수직(perpendicular)이다. 즉 내적(dot product)을 했을 때 결과가 0이어야 한다. 식이 맞는지 확인해보도록 하자. 

 

 

 

식을 곱해서 전개하면 분수의 분모가 캔슬되고 분자만 남게되고(분수의 계산 결과는 상수임을 기억하자), 결과는 0이 된다. q1과 q2가 직교(orthogonal)임을 식의 전개를 통해 확인하였다. 

 

우리는 지금까지 두 개의 독립인 벡터 a와 b를 가지고 a를 기준으로 서로 직교(orthogonal)인 벡터 q1과 q2를 만들었다. 이제 세 번째 벡터 q3를 만들어보자. q3를 만들기 위해선 a와 b와 독립인 벡터 c가 필요하다. Fig. 1의 a와 b에서 화면으로 나오는 방향, 혹은 들어가는 쪽으로 비스듬하게 독립인 벡터 c가 있었다고 가정해보자(이때의 행렬은 3x3크기의 full rank=3인 행렬). Fig. 3은 a와 b로부터 q1과 q2를 만든 모습이다. 아래의 Fig. 4는 이 시점에서부터 시작한다. 

 

 

Fig. 4 독립 벡터 c의 그람-슈미트 과정 첫 번째 단계. 왼쪽 그림은 옆에서 바라본 장면이다. 

(2D로 표현하기에는 한계가 있어서 3D-CAD툴을 이용하여 표현하였다)

 

 

Fig. 4는 독립인 벡터 c를 q1과 q2에 동시에 직교(orthogonal)한 벡터로 만드는 그람-슈미트 과정의 첫 번째 단계를 나타낸다. 파란색 벡터 c는 독립이긴 하지만 q1과 q2어느 누구와도 직교는 아닌 상태이다(Fig. 4의 왼쪽 side view 참고). 여기서 우리가 해야할 일은 c를 q1과 q2에 동시에 직교하게 만들어야 하는데, 먼저 q1과 직교하게 만들고 그 다음 q2와 직교하게 만들면 된다. Fig. 4는 이 중 q1과 직교하게 만드는 과정을 나타낸다. 

 

벡터 c를 a에 투영시키면 녹색 벡터 p를 얻을 수 있고, p=xa와 ec1=c-p에 의해 a와 직교한 에러 벡터 ec1을 구할 수 있다. 이 과정은 식 (1)과 같은 과정이며, e->ec1, b->c, 와 같이 c에 맞게 바뀐 것이다. 이것을 식으로 나타내면 아래와 같다. 

 

 

벡터 c로부터 이렇게 q1과 직교인 에러 벡터 ec1을 만들어냈다. q1과 직교인 벡터를 만들어 냈으니 다음은 q2와 직교한 벡터를 만들 차례다. 아래 그림은 Fig. 4에 이어 q2와 직교한 벡터를 만드는 과정을 나타낸다. 

 

 

 

Fig. 5 q2와 직교한 벡터 ec2를 만드는 과정. 결과적으로 에러 벡터 ec2는 q1과 q2에 동시에 직교하므로 ec2=q3이다. 

 

 

 

q1과 직교한 벡터 ec1을 q2에 투영시키면 벡터 p를 얻고, 이 둘 사이의 에러 벡터인 ec2=ec1-p를 계산해주면 최종적으로 ec2를 구할 수 있다. Fig. 5에서 보는 것과 같이 ec2는 q1과 q2모두에 직교한 벡터이기 때문에 결과적으로 ec2=q3가 된다. 이를 식으로 나타내면 아래와 같다. 

 

 

약간 복잡해 보이지만 그리 어렵지 않으니 차근차근 확인해보자. 먼저 ec2는 앞서 구한 ec1에서 투영 벡터 p를 빼주면 구할 수 있는데, 이때 투영 벡터 p는 q2에 어떤 스칼라(scalar)상수를 곱한 것과 같다. 이 예에선 음수 값이 될 것이다. 그리고 ec2는 q2와 직교 하기 때문에 내적(dot product)을 해주면 그 결과가 0이 된다. 이러한 정의들을 가지고 식을 치환하고 전개해서 풀어주면 x에 관한 식을 (4.1)과 같이 구할 수 있다. 

 

 

그 다음 ec2=ec1-p에서 p를 x q2로 치환한 후 (4.1)의 x를 대입해주면 (4.2)와 같은 식을 구할 수 있다. 그런데 식에 ec1이 있어서 약간 혼란스러울지도 모르겠다. ec1을 식 (3)에서 정의한 내용으로 치환하여 다시 정리하면 아래와 같다. 

 

 

 

식이 많이 길지만 겁먹을 건 없다. 그저 치환해서 정리한 것 뿐이다. 먼저 (5.1)은 (4.2)의 분수의 분자에 있는 ec1을 (3)으로 대체하여 정리한 것이고 (5.2)와 같이 전개된다. 이때 분자에 q2 transpose와 q1을 내적하는 부분이 있는데, q1과 q2는 직교(orthogonal)이기 때문에 0이 되어 사라지고 (5.3)과 같이 된다. 이제 (5.3)의 ec1을 (3)으로 대체하여 정리해주고 ec2를 q3로 바꿔주면 최종적으로 식 (5.5)와 같이 정리된다. 

 

이렇게 하여 임의의 독립(independent)인 column 벡터 a, b, c로부터 같은 column space를 공유하면서 직교(orthogonal)하는 직교 벡터(orthogonal vector) q1, q2, q3를 구하였다. 다시 한 번 식을 한 번에 정리해보자. 

 

 

 

 

q1은 굉장히 쉽게 구했다. 그냥 첫 번째 벡터인 a를 대입하면 된다. q2는 b의 투영을 통해 a와 직교한 에러 벡터(error vector) e를 구하는 식이다. 마지막 q3는 c를 q1과 q2에 순차적으로 투영시켜 에러 벡터를 구하게 된다. q3의 패턴을 살펴보면 원래의 벡터 c에서 q1으로 투영시킨 벡터, q2로 투영시킨 벡터를 각각 빼준다. 여기서 한 가지 중요한 사실은 만약 4차원, 5차원, n차원 column vector가 더 있다면 q4, q5, qn을 위와 같은 패턴으로 구할 수 있다는 것이다. 물론 조건은 독립(independent)이어야 한다. 만약 q4를 구해야 한다면 원래 벡터인 d에서 q1, q2, q3로 각각 투영시킨 벡터들을 빼주면 된다. 이것이 Gram이 제안한 직교벡터를 만드는 아이디어이다. 

 

마지막으로 q3를 구하는 과정을 하나의 그림으로 살펴보고 다음으로 schmidt가 제안한 아이디어를 알아보도록 하자. 아래 그림은 q3를 구하는 과정을 하나의 그림으로 표현한 것이다. Fig. 4와 Fig. 5를 하나로 합친 것으로 생각하면 된다. 벡터 c부터 시작한다. 

 

 

Fig. 6  q3를 구하는 과정. 벡터 c부터 시작

 

 

 

- (2) Making Orthonormal Vectors (by Schmidt)

 

그 다음 과정은 상대적으로 간단하다. 지금 까지 구한 직교 벡터(orthogonal vector)는 정규화(normalized)가 되어 있지 않다. 즉, 각 벡터의 크기가 제각각이다. 이들을 방향 성분만을 나타내는 벡터로 만들기 위해선 정규화를 통해 정규직교벡터(orthonormal vector)로 만들어 줘야한다. 정규직교벡터를 만드는 방법은 각 벡터를 자신의 크기로 나누어 주면 된다. 

 

 

 

기존의 직교 벡터(orthogonal vector)와 구분해주기 위해 q hat으로 표현을 했다. 이렇게 직교 벡터로부터 정규직교벡터를 만드는 것은 schmidt의 아이디어이다. 

이렇게 해서 기존의 독립(independent)인 column vector a, b, c로부터 정규직교벡터(orthonormal vector) q1, q2, q3를 만들어냈다. 이 실제 벡터를 이용해서 계산해 보도록 하자. 

 

 

 

5. 예제와 MATLAB 구현

 

- 2D subspace in R3

 

아래의 두개의 독립인 3차원 벡터를 그람-슈미트 방법(Gram-Schmidt Process)을 이용하여 정규직교벡터(orthonormal vector)로 만들어보자. 벡터 a와 b는 3차원 공간에 존재하는 벡터들이며, 이 두 벡터가 이루는 column space는 2차원 평면 임을 알아두자. 

 

 

 

먼저 식 (6.1)과 (6.2)를 이용하여 직교 벡터(orthogonal vector)로 만들면 아래와 같다. 

 

 

 

 

직교 벡터 q1과 q2는 구했고, 이제 정규화를 해보자. q1과 q2를 각각의 크기로 나누어주면 아래와 같이 단위 벡터가 만들어진다. 

 

 

 

이렇게 하여 a와 b로부터 정규직교벡터(orthonormal vector) q1과 q2를 구하였다. 이렇게 계산한 q1(hat)과 q2(hat)로 직교 행렬(orthogonal matrix)을 만들 수 있는데, 간단히 q1(hat), q2(hat), ... qn(hat)을 순서대로 column vector로 삽입하면 된다

 

 

우리는 기존의 행렬 A로부터 직교행렬 Q를 만들었다. 이미 언급했지만 여기서 column space에 관한 얘기를 한 번 더 해보자. column space라는 것은 column vector들의 가능한 모든 선형 조합(Linear Combination)을 통해 형성하는 공간을 의미한다. 그렇다면 원래의 행렬 A와, A로부터 만든 직교행렬 Q와는 무슨 관계가 있을까? A와 Q의 column space는 똑같은 공간을 공유한다. 즉 원래의 행렬 A의 column vector들은 column space의 기저(basis)이며, 선형 조합을 통해 column space를 형성한다. 마찬가지로 Q의 column vector들도 기저(basis)로써 A와 같은 공간을 형성하는데, 기저가 정규직교벡터(orthonormal vector)이기 때문에 A보다는 계산 등에 훨씬 유리하다. 정리하자면 A의 column space의 기저(basis)를 보다 효율적이고 최적화된 기저로 만드는 방법이 그람-슈미트 방법(Gram-Schmidt Process)이라고 생각하면 된다. 

 

MATLAB구현을 보기 전에 q1(hat)과 q2(hat)가 직교인지 확인해보자. 내적(dot product)을 하여 결과 값이 0이 나오는지 확인하면 된다. 

 

 

 

내적 결과 값이 0이므로 q1과 q2가 직교한다는 사실을 확인했다. 

 

 

아래 그림은 위의 q1과 q2를 MATLAB을 이용하여 구현한 것이다. 

 

Fig. 7 Gram-Schmidt Process를 이용한 정규직교벡터의 그래프

 

 

Fig. 7은 식 (8)의 벡터 a, b와 이를 그람-슈미트를 이용하여 정규직교벡터로 만든 q1(hat), q2(hat)를 그래프로 나타낸 것이다. 보다시피 원래의 벡터 a와 b는 독립이며 노란색으로 표현된 column space를 "span"할 수 있다. 그러나 a와 b의 선형 조합(Linear combination)을 이용하여 column space를 표현할 경우 계산상에 많은 불리함이 있다. 

 

보라색과 하늘색 벡터는 a와 b를 정규직교벡터로 만든 q1(hat)과 q2(hat)이다. 앞서 말했듯이 q1(hat)은 a를 그대로 대입하고 정규화 했기 때문에 a와 같은 선상에 위치한 것을 볼 수 있다. q1(hat), q2(hat)는 a와 b로 형성했던 column space와 같은 공간에 위치한 것을 볼 수 있으며, 같은 column space를 "span"하더라도 계산상에 있어 훨씬 유리한 점이 많다. 이 점에 대해서는 지난 강의 Lecture 17-(1)에 언급해 놓았으니 참고하기 바란다. q1(hat)과 q2(hat)는 90도 각도를 이루고 있음을 볼 수 있다. Fig. 7에 보이는 그래프에서는 완벽한 90도가 아닌 것 처럼 보일 수는 있으나 이것은 MATLAB그래프의 가로 세로의 비율(aspect ratio)과 바라보는 각도때문에 왜곡이 생겨서 그렇다. 실제로는 90도를 이루고 있다. 

 

직교성을 확인하기 위해 MATLAB에서 계산한 q1(hat)과 q2(hat)를 실제로 내적하면 정확하게 0이 안나오는 경우가 생긴다. 이는 컴퓨터로 계산할 때 발생하는 round off 에러 때문인데, 컴퓨터의 수치 정밀도 때문에 발생하는 것이다(자세한 것은 구글 참조). 실제로 Fig. 7의 q1(hat)과 q2(hat)의 내적을 계산하면 1.6653e-16 이라는 수치가 나오는데, 엄청나게 작은 수 이므로 0으로 간주하는 것이다. 아래의 첨부된 MATLAB 코드를 참조하여 실제로 구현해서 확인해보는 것을 추천한다. 

 

 

 

 

- 3D space

 

이번에는 a, b에 이어 c가 추가된 3차원 column space에 대한 그람-슈미트 과정(Gram-Schmidt Process)을 수행해보도록 하자. 벡터 c는 아래와 같다. A는 c가 추가된 행렬을 나타낸다. 

 

 

 

q1과 q2는 이미 구했으니 c와 관련된 q3만 구하면 된다. 식 (6.3)을 이용하여 계산해보자. 

 

 

 

 

 

계산하다보니 숫자가 좀 커졌지만, 어쨋든 q3를 구하였다. 이제 정규화(normalization)를 통해 q3를 정규직교벡터로 만들어보자. 

 

 

 

 

 

이렇게하여 a, b, c로부터 정규직교벡터 q1(hat), q2(hat), q3(hat)를 만들었다. 직교행렬(orthogonal matrix)을 만드는 것은 식 (11)과 같기 때문에 넘어가도록 하겠다. 직교성을 확인하기 위해 q1(hat), q2(hat)와 내적하는 것은 MATLAB을 이용하거나 직접 해보길 바란다. 아래 그래프는 식 (13)의 벡터와 이에 대한 그람-슈미트 과정을 통해 얻은 정규직교벡터를 나타낸다. 

 

 

Fig. 8 식 (13)의 벡터와 그들의 정규직교벡터 그래프

 

Fig. 8을 보면 기존의 독립 벡터 a, b, c는 3차원 공간을 "span"하기는 하지만 크기도 제각각이고 column space인 3차원 공간의 기저(basis)가 되기엔 뭔가 최적화 되어 있지 않아 보인다. 반면 그람-슈미트 과정을 통해 만든 정규직교벡터 q1(hat), q2(hat), q3(hat)는 정규화된 동일한 크기의 벡터이고 서로 완벽하게 직교(orthogonal)를 이루는 모습을 볼 수 있다. 아래는 이를 구현한 MATLAB 코드이다. 

 

 

 

 

 

이번 포스팅에서는 3차원 정규직교벡터인 q3까지 구하였다. 하지만 이전에도 언급했듯이 4차원, 5차원, n차원의 벡터에 대해서도 계산은 가능하다. q1->q2->q3로 가면서 계산하는 패턴은 동일하기 때문에 n차원 그람-슈미트 방법에 대한 구현도 어렵지않게 할 수 있을 것이다. 

 

 

 

6. QR분해(QR decomposition)

 

- QR decomposition basic

 

마지막으로 살펴볼 내용능 지금까지 계산했던 그람-슈미트 방법(Gram-Schmidt Process)을 행렬로 정리하는 것이다. 이를 QR 분해(QR decomposition, QR factorization)라고 한다. 그러나 여기에선 그리 많은 양을 다루진 않고 간략히 살펴보고 넘어가도록 하겠다. 나중에 기회가 되면 따로 정리하도록 하고 일단 이런게 있구나 정도만 보고 넘어가면 될 것 같다. 

 

우리는 지난 Lecture 4에서 A=LU 분해(A=LU decomposition)를 배웠다. A라는 행렬을 소거 행렬(elimination matrix)을 통해 삼각행렬(triangular matrices)들의 곱으로 분해해서 표현하는 방법인데, QR 분해 역시 마찬가지로 원래의 A행렬을 Q행렬과 R행렬의 곱으로 분해하여 표현하는 방법이다. 여기서 Q행렬은 우리가 지금까지 그람-슈미트 방법을 통해 구했던 직교 행렬(orthogonal matrix)을 의미하며, R행렬은 A와 Q를 연결시켜주는 행렬이라고 생각하면 된다. 특히 R행렬은 상삼각행렬(Upper triangular matrix)의 형태를 띄고 있는데, 지금부터 이 R행렬이 무엇이고 왜 상삼각행렬의 모양으로 하고 있는지 알아보자. 

 

행렬 A와 Q, R은 아래와 같이 나타낼 수 있다. 

 

 

 

위의 식 (16)을 보고 어떤 사람들은 이렇게 생각할지도 모르겠다. 아까 분명히 Q행렬을 만들 때 q1, q2, ... 들을 순서대로 Q의 column vector에 삽입하면 된다고 했는데, 왜 갑자기 Q가 m x m이 되는 거지? 사실 식 (16)은 QR 분해를 할 때 A가 정방행렬(square matrix)의 형태 뿐만 아니라 직사각행렬(rectangular matrix)의 형태까지 고려한 일반적인 형태이다. 직사각행렬인 경우 계산 과정이 약간 더 복잡해진다. 이에 대한 자세한 내용은 QR분해 위키를 참조하도록 하고 일단 정방행렬인 경우만 고려하여 생각하도록 하자. 

 

우선 A행렬의 column vector들을 a1, a2, ...로 표현했는데, 위에서 설명한 a, b, c, 등의 벡터를 나타낸다. Q행렬은 A와 똑같은 column space를 형성하는 기저(basis)들로 구성되어 있으며 정규직교벡터들로 구성되어 있다. 중요한건 R행렬인데, 각 원소들은 a1, a2 등의 벡터들과 Q행렬의 column vector인 q1, q2 벡터들과의 내적으로 구성되어 있다. 그런데 대각선을 기준으로 아래쪽 원소들은 전부다 0이 된다. 왜 그럴까? 

 

아래쪽 원소의 식을 보면 a1과 q2, 그리고 a2와 q3와 같이 q벡터와 이전 index의 벡터들과 내적을 한다. 어째서 어떤 q벡터와 이전 index의 a벡터와 내적을 하면 0이 될까? 그것은 그람-슈미트의 계산 과정과 관련이 있다. 식 (6.3)이나 Fig. 6을 보면 우리가 벡터 c로부터 q3를 만들 때 먼저 q1과 직교하게 만들고, 그 다음 q2와 직교하게 만들어서 q3를 생성하게 된다. 이 말은 qn을 만들 때 qn-1과는 반드시 직교(orthogonal)해야하고 따라서 q1, q2등과 대응 되는 a, b, c, ... 등의 이전의 모든 벡터와는 직교해야함을 의미한다. 따라서 아래쪽 삼각형 원소들은 모두 0이 되고 R은 상삼각행렬(upper triangular matrix)의 형태가 된다. 

 

 

- QR matrices and MATLAB function

 

Q행렬은 그람-슈미트 과정을 통해 얻은 q벡터들을 Q의 column vector들로 삽입하여 간단히 얻을 수 있다고 하였다. 그렇다면 R행렬은 어떻게 구할 까? A행렬이 정방행렬(square matrix)이라고 가정할 때, 아래의 식을 통해 간단히 얻을 수 있다. 

 

 

결국 원래 행렬 A에 Q transpose행렬을 곱해주면 R을 얻을 수 있다. 아래 그림은 식 (13)을 MATLAB을 이용하여 계산한 결과다. 

 

Fig. 9 식(13)의 QR decomposition

 

 

기존에 구했던 q1, q2, q3를 이용하여 직교행렬 Q를 만든 다음, 식 (17)과 같이 R을 계산하고 Q와 R을 곱하여 식이 맞는지 확인하였다. 결과적으로 A와 같음을 볼 수 있다. 

 

그런데 MATLAB에는 행렬 A만 있으면 기본적으로 QR decomposition을 해주는 함수가 있다. 명령어는 " [Q R]=qr(A) " 와 같이 치면 되고 자동으로 Q와 R행렬을 계산해준다. 그러나 Fig. 9에서 계산한것과 부호 등이 다른 경우가 있는데, 이는 구현 알고리즘이 달라서 발생하는 현상이며 결국은 같은 기능을 하는 것이다. 실제 구현에서는 Householder reflection방법을 많이 사용하는데, 수치계산에 있어서 그람-슈미트보다 훨씬 안정적이라고 한다. 자세한 사항은 QR분해 위키를 참조하자. 아래는 MATLAB내장함수인 qr()을 이용하여 계산한 결과다. Fig. 9의 결과와 비교해보자. 

 

Fig. 10 MATLAB내장 함수를 이용하여 수행한 QR decomposition

 

 

 

7. 마치며

 

이번 포스팅에선 그람-슈미트 방법(Gram-schmidt Process)에 대해서 공부하였다. 그람-슈미트는 기존 행렬의 column space를 이루는 기저(basis)를 계산에 있어서 보다 효율적이고 최적화된 기저로 바꾸는 방법이며, 바뀐 기저는 정규직교벡터(orthonormal vector)의 형태를 띈다. 이는 계산 상에 있어 여러 모로 효율적이다. 정규화된 단위 벡터이기 때문에 크기는 1이며, 방향 성분만을 나타내는 벡터이다. 따라서 overflow, underflow등과 같은 문제에 있어 자유롭고, 계산을 간단하게 해주는 특징을 보인다. 

그람-슈미트 방법은 기본적으로 투영(projection)의 개념을 이용하여 계산되며, 이 그람-슈미트 방법은 이후 SVD(singular value decomposition)에 응용 되기도 하니 잘 알아두도록 하자. 

 

이번 강의에서 배울 내용은 직교행렬(Orthogonal Matrix)과 그람 슈미트 과정(Gram-Schmidt Process)이다. 먼저 이들을 간략히 설명하면 다음과 같다. 직교 행렬은 모든 column vector가 자기 자신을 제외한 나머지 모든 column vector들과 직교이면서 크기가 1인 단위 벡터들로 구성된 행렬을 의미한다. 그리고 그람 슈미트 과정은 임의의 독립 행렬(independent matrix)로부터 각 column vector가 정규직교(Orthonormal)한 벡터들로 구성된 직교 행렬을 만드는 과정 혹은 방법을 의미한다. 이 설명만 가지고는 이해하기가 어려울 수 있으니 차근차근 공부해 보도록 하자. 먼저 정규직교벡터(Orthonormal vector)에 대해 공부해보자. 

 

 

 

1. 정규직교벡터(Orthonormal Vector)

 

- 단위 벡터(Unit Vector)

 

정규직교벡터(Orthonormal Vector)를 알아보기 전에 먼저 단위 벡터에 대해 먼저 알아보도록 하자. 

 

일반적으로 어떤 벡터는 크기와 방향 성분을 가진다. 예를 들어 벡터 vv=[2 1]T라고 했을 때, v는 바닥에서 약 26.5도 회전한 쪽으로의 방향을 가리키고 있고, √5의 크기를 갖는다. 여기서 어떤 scale상수를 곱해서 벡터의 길이를 늘린다고 가정해보자. scale상수가 3이면 3 x v = [6 3]T = √45 = 3√5의 크기가 된다. 즉 원래 벡터의 길이에 곱해진 scale만큼 길이가 더 늘어나게 된다. 

 

그렇다면 단위 벡터(Unit Vector)란 무엇인가? 정의하자면 길이가 1인 벡터를 의미한다. 즉 길이가 1이라는 것은 단위 길이(Unit length)를 의미하며 오직 방향성분만을 나타내는 벡터이다. 우리가 길이를 나타낼 때 표준 단위계(SI)에선 m(meter)을 이용하여 길이를 표현한다. 가령 2미터를 나타낼 때 "2m"과 같이 숫자 뒤에 m을 붙여주는데, 이때 m은 길이의 단위를 나타낼 뿐 실제 길이에 어떠한 영향도 끼치지는 않는다. 

단위 벡터는 바로 "m"과 같은 역할을 하는 것이다. 힘의 크기와 방향 등을 벡터로 나타낼 때 단위 벡터(Unit vector)는 크기 성분에는 전혀 영향을 끼치지 않는다. 방향 성분만을 나타내기 때문에 어떤 scale상수를 곱하여 길이를 늘린다고 했을 때 그 늘린 길이가 scale상수 그 자체이다. scale이 3, 벡터 v가 단위 벡터라고 했을 때 3 x v의 길이(크기)는 3이다. 

 

일반 벡터를 단위벡터로 만들기 위해선 아래 식과 같이 기존의 벡터를 벡터의 크기로 나누어주면 된다. 

 

 

식 (1)을 참고하여 벡터 v=[2 1 3]T를 단위벡터(Unit vector)로 만들어보자. 

 

 

 

우리는 이러한 단위 벡터를 정규화 벡터(normalized vector)라고도 한다. 즉 서로 다른 스케일을 가지고있는 벡터들을 동일한 스케일에서 바라보기위해 벡터의 크기로 나누어 정규화(normalization)한 벡터를 의미한다. 

 

 

 

- 정규직교벡터(Orthonormal vector)

 

직교 벡터(orthogonal vector)는 알다시피 벡터 사이의 각도가 90도, 즉 직각(perpendicular)을 이루는 벡터를 말한다. 즉 어떤 a라는 벡터가 있고, a와 직각인 벡터 b가 있을 때 a와 b벡터를 우리는 직교벡터라고 하며 이때 a와 b의 내적(dot product)은 0이 된다. 따라서 직교 벡터는 어떤 하나의 벡터로는 정의할 수 없고 반드시 한 쌍 이상의 벡터로부터 정의되어야 한다

 

그렇다면 정규직교벡터(orthonormal vector)란 무엇일까? 이는 바로 직교 벡터(orthogonal vector)이면서 단위 벡터(unit vector)인 벡터를 말한다. 즉 두 벡터가 90도의 각도를 이루고, 각 벡터의 길이(크기)는 1인 방향성분만을 나타내는 벡터를 우리는 정규직교벡터(orthonormal vector)라 한다. 이를 수식으로 나타내면 아래와 같다. 

 

 

Orthonormal vector를 각각 qi, qj라고 했을 때, qi는 자기 자신에게는 직교(orthogonal)하지 않는다. qi를 자기 자신과 곱하면, 즉 자기 자신과 내적(dot product)하면 그 결과값은 1이 된다. 이것이 의미하는 것은 q는 벡터의 크기가 1인 단위 벡터(unit vector)라는 의미다. 단위 벡터인 식 (2)의 v hat을 제곱해보자. 결과는 4/14 + 1/14 + 9/14 = 1이 될 것이다. 이처럼 벡터들이 서로 직교(orthogonal)하면서 동시에 정규화된 벡터이기 때문에 ortho-normal이라는 이름을 사용하는 것이다. 

 

자기 자신을 제외한 나머지 모든 벡터들과는 직교(orthogonal)한다. 즉 자기 자신을 제외한 나머지 벡터들과의 내적(dot product)결과가 0이 되는 것이다. 아래 그림은 이러한 정규직교벡터(orthonormal vector)의 한 예를 나타낸다. 

 

 

Fig. 1 정규직교벡터(orthonormal vector)의 예

 

 

Fig. 1은 sin과 cos으로 이루어진 벡터를 나타낸다. 이들 벡터 a, b의 길이는 각각 1이며 둘 사이의 각도는 90도이다. 두 벡터가 직교(perpendicular)하며 각 벡터의 길이는 1로써 방향성분만을 나타내므로 이들은 정규직교벡터이다. 

 

이러한 정규직교벡터들을 행렬의 column vector에 삽입하면 직교행렬(orthogonal matrix)이 된다. 즉 Q를 직교행렬이라고 했을 때 orthonormal vector들이 Q의 정규직교기저(orthonormal basis)가 되는 것이다. 이러한 정규직교기저는 선형대수의 행렬 계산에 있어 좋은 결과를 보여준다. 특히 선형대수계산을 연구하는 분야인 Numerical Linear Algebra의 대부분의 연산은 이러한 orthonormal vector를 기반으로 이루어진다. 이들은 수치 연산을 하는 과정에서 값이 무한정 커지거나 작아져서 발생하는 overflow나 underflow문제에 있어서 자유롭다. 왜냐하면 크기에 영향을 미치지않는 단위 행렬(unit vector)성분을 가지고 있기 때문이다. 이것이 정규화(normalization)의 힘이다.

 

 

 

2. 직교행렬(Orthogonal Matrices)

 

- Basic of Orthogonal Matrix

 

직교행렬(orthogonal matrix)은 행렬의 row와 column vector들이 자기 자신을 제외한 나머지 모든 row, column vector들과 직교(perpendicular)이면서 동시에 단위 벡터(unit vector)인 행렬을 의미한다. 즉 orthonormal vector들을 행렬 Q에 집어넣은 것과 같다. 아래 식과 같이 말이다.  

 

 

 

식 (4)는 orthonormal vector를 행렬 Q에 column vector로써 삽입한 형태이다. 이때 임의의 벡터 qi는 자기 자신을 제외한 나머지 벡터들과 직교(perpendicular)하다. 즉 식 (3)의 규칙을 따르는 것이다. 식 (3)의 규칙을 확인하기 위해서는 Q transpose와 Q를 곱한 값을 보면 알 수 있다. 

 

 

식 (5)는 Q transpose와 Q의 곱셈 결과를 나타낸다. Q transpose는 q transpose를 Q의 row vector로 삽입한것과 같다. 이를 Q와 곱하면 어떤 결과가 나오는가? 바로 단위 행렬(Identity matrix)이다. Q transpose의 row1과 Q의 col1의 곱은 자기 자신과의 곱셈이다. 따라서 모든 row(i)와 col(j), (i=j)의 곱셈은 자기 자신과의 곱셈이기 때문에 결과 행렬의 대각 성분은 1이 된다. 반면 나머지 벡터끼리의 곱셈은 직교(orthogonal)하기 때문에 0이 되어 결과적으로 단위 행렬이 나오는 것이다. 결국 

는 

와 마찬가지로 모든 row와 column 벡터들 끼리의 내적(dot product)을 확인하는 것이다. 식 (3)의 정의와 맞는 것을 볼 수 있다. 

 

이렇게 하여 우리는 orthonormal column을 가진 orthogonal matrix를 배웠다. 사실 Q에 대한 더 정확한 표현은 orthonormal matrix이다. 각 벡터들이 orthogonal이 아닌 orthonormal한 벡터를 가지고 있기 때문이다. 그러나 무슨 이유에서인지 표현은 항상 orthogonal matrix로 한다

 

 

- Square Orthogonal Matrix

 

직교 행렬(orthogonal matrix)이면서 정방행렬(square)인 경우의 가장 대표적인 예는 단위행렬(identity matrix)이다. 단위행렬의 각 column vector는 자기 자신을 제외한 나머지 벡터들과 90도의 각도를 이루면서 각각의 크기는 1이다. 이를 시각화하면 아래 그림과 같다. 

 

Fig. 2 직교행렬(orthogonal matrix)이면서 정방행렬(square matrix)인 단위행렬(identity matrix)의 시각화

 

 

Fig. 2는 어디서 많이 본 그림일 것이다. 바로 표준 기저(standard basis)이다. x축은 y축과 z축에 각각 수직(perpendicular)이며, y는 x와, z축에, z는 x와 y에 각각 수직이다. 각 벡터끼리 내적(dot product)을 하면 0이 되는 것을 볼 수 있다. 또한 각 축의 기저는 정규화(normalized)된 크기인 1이다. 이러한 표준 기저의 선형 조합(Linear combination)을 통해 우리는 3차원 공간의 모든 벡터, 점 등을 정의할 수 있다. 

 

이와 같이 직교 행렬이 정방행렬일 경우 한 가지 흥미로운 특성을 갖는다. 그것은 바로 transpose가 역행렬(inverse matrix)과 같다는 것이다. 다시 정리해보자면

 



정규직교벡터(orthonormal vector)로 구성된 직교 행렬(orthogonal matrix) Q가 row의 수와 column의 수가 같은(m=n) 정방행렬(square)인 경우
의 관계에 의해서 Q의 transpose는 Q의 역행렬(inverse matrix)이 된다. 즉





 

 

사실 식 (5)를 잘 살펴보면 당연하다. Q transpose와 Q를 곱했을 때 단위행렬이 된다는 것은 Q가 정방행렬인 상황에서 Q transpose가 당연히 역행렬이어야 한다. 예를 한 번 들어보자. 우리는 지난 Lecture 5에서 행 교환(row exchange)연산을 해주는 치환행렬(permutation matrix)에 대해 공부했었다. 치환행렬은 정규직교벡터로 구성된 직교 행렬(orthogonal matrix)이다. 아래 식을 보자. 

 

 

 

식 (6)의 치환행렬(permQ)의 column vector나 row vector들은 각자의 크기는 1이면서 자기 자신을 제외한 나머지 벡터들과는 수직(perpendicular)이다. 이제 여기에 Q의 transpose를 곱해보자. 결과는 아래와 같다. 

 

 

직교 행렬 Q에 Q transpose를 곱했더니 단위행렬이 나오는 것을 볼 수 있다. 따라서 Q transpose는 Q의 역행렬과 같다. 

한 가지 예를 더 들어보자. Fig. 1과 관련이 있는 예다. 

 

 

식 (8)은 cos과 sin으로 이루어진 직교 행렬(orthogonal matrix)이다. column 벡터들을 보면 각각 col1=[cos sin]T, col2=[-sin cos]T인데, 둘은 Fig. 1에 보이는 것과 같이 직교하며 내적(dot product)을 하면 0이 된다. 각 column vector의 크기는 1이며, 크기 구하는 식에 대입해보면 바로 알 수 있다. 

 

 

 

 

한 가지 예를 더 들어보자. 아래의 행렬은 직교 행렬인가? 

 

 

분명 column 혹은 row vector를 비교해보면 직교 벡터를 가지고 있다. 그러나 각 벡터의 길이가 1이 아니다. 어떻게 이들의 길이를 1로 만들어줄 수 있을까? 위의 단위 벡터 편에서 단위 벡터를 만들기 위해선 벡터의 크기로 나눠주면 된다는 것을 배웠다. 마찬가지로 벡터의 크기로 행렬 원소 전체를 나눠주면 된다. 다음 식과 같이 말이다. 

 

 

식 (11)의 임의의 qi의 길이(크기)를 계산해보면 √(1/2+1/2)=√(1)=1이 되는 것을 알 수 있다. 사실은 column 1과 column 2가 직교(orthogonal)하지만, 크기가 다를 경우가 있다. 따라서 보다 정확하게 말하자면 column 1은 column 1의 크기로, column 2는 column 2의 크기로 각각 나누어줘야 한다

 

이제 마지막 예를 들어보도록 하겠다. 다음 행렬을 살펴보자. 식 (10)의 행렬을 반복하여 만든 행렬이다. 

 

 

식 (12)는 식 (10)의 행렬 Q의 각 원소들에 Q를 대입한 것과 같은 형태이다. 먼저 직교성(orthogonality)을 계산해보면 Q의 임의의 column qi와 나머지 column vector와 내적을 하면 결과는 0이 된다. 그러나 각 column 혹은 row vector의 길이는 1이 아니다. 즉 직교성은 만족하지만, 단위 행렬(unit vector)속성은 만족하지 않는다. 따라서 직교행렬이 되기 위해선 식 (11)과 같이 단위 행렬로 만들어야 한다. 이를 위해서 해당 column 혹은 row 벡터의 길이(length or magnitude)로 자기 자신을 나누어주면 된다. 

 

 

식 (13)의 어떠한 벡터의 크기를 계산해도 1이 된다. 따라서 식 (13)은 직교 행렬(orthogonal matrix)이다. 식 (13)의 행렬을 특히 Adhemar matrix이라고 부른다. 이에 대한 자세한 것은 구글을 참고하자. 여기선 그냥 넘어가도록 하겠다. 

 

 

- Rectangular Orthogonal Matrix

 

지금까지는 직교 행렬(Rectangular Matrix)이 정방행렬인 경우만 살펴보았다. 이번엔 임의의 직사각 형태인 직교 행렬을 살펴보도록 하자. 아래 식은 직사각 형태의 직교 행렬을 나타낸다. 

 

 

 

식 (14.1)일 때는 그저 단순히 하나의 단위 벡터(unit vector)이다. 여기에 col1벡터와 독립인 col2벡터를 추가하여 (14.2)와 같은 직사각형 형태(Rectangular) 식을 만들었다. 이때의 column vector들은 3차원 공간에서 2차원 부분 공간(subspace)의 column space를 이루는 기저(basis)가 된다. 여기에 세 번째 column vector를 더하면 (14.3)과 같이 된다. 

 

사실 여기서 말하고자 하는 것은 (14.1)에서 (14.2)로 넘어갈 때, 그리고 (14.2)에서 (14.3)으로 넘어갈 때 어떻게 직교벡터(orthogonal vector)를 만드느냐이다. 특별한 알고리즘이나 방법이 없이는 우리의 직관에 의해서 직교 벡터들을 만들어서 기존의 행렬에 더해줘야 한다. 그러나 이는 행렬의 크기가 커질 수록 너무나 어려운 일이다. 이후에 설명할 그람-슈미트 과정(Gram-Schmidt Process)은 이러한 직교 행렬을 만들어주는 특별한 방법이다. 즉 임의의 독립된 column vector들로 구성된 행렬, 즉 독립(independent)인 행렬(matrix)이 있을 때, 이 독립인 행렬을 직교행렬(orthogonal matrix)로 만들어주는 방법이다. 

 

본격적으로 그람-슈미트 과정을 공부하기 전에 먼저 직교 행렬을 이용하여 연산을 했을 때 어떠한 이점이 있는지 살펴보도록 하자. 

 

 

- Advantage of using Orthogonal Matrix

 

직교 행렬(orthogonal matrix) Q를 활용하여 계산하면 몇 가지 이점이 있다. 먼저 수식이 굉장히 간단해진다. 우리가 어떤 벡터 b를 행렬 A의 column space로 투영(projection)시키고 싶을 때, 투영행렬(projection matrix)을 통해 이를 할 수 있음을 Lecture 15에서 배웠다. 투영 행렬의 식을 다시 상기시켜보자. 

 

 

식 (15)의 투영행렬식은 얼핏 보면 약간 복잡해 보이긴 한다. 그렇다면 A대신 Q를 이용하여 투영행렬을 만들게 되면 식이 어떻게 변할까? 

 

 

Q는 정규직교(orthonormal) column vector들로 이루어진 직교 행렬(orthogonal matrix)이다. A대신 Q를 이용하여 투영 행렬(projection matrix)를 만들었더니 식 (16)과 같이 식이 굉장히 간단해졌다. 괄호 안의 Q transpose Q가 식 (5)에서 본 것과 같이 단위행렬이 되기 때문이다. 따라서 괄호 안의 식은 없어지는 것과 마찬가지가 되고 결국 양 끝에 Q와 Q transpose만 남게 된다. 이때 Q가 임의의 직사각행렬(rectangular matrix)이라면, (16)의 결과 행렬은 대칭 행렬(symmetric matrix)이 된다. 

 

만약 Q가 정방행렬(square matrix)이라면 어떨까? 이 경우엔 식이 훨씬 더 단순해진다. 우리는 위의 노란박스에서 Q가 정방행렬일 경우 Q의 전치(transpose)는 Q의 역행렬이라고 배웠다. 식 (16)에서 Q의 투영행렬은 

이 되므로 결과적으로 단위 행렬이 된다. 식은 아래와 같다. 

 

 

왜 Q가 정방행렬일 경우 투영행렬이 단위 행렬이 되는지 잘 생각해보자. 투영 행렬은 임의의 벡터 b를 행렬 A 혹은 Q의 column space로 투영(column space의 가장 가까운 벡터로의 매칭)시키는 역할을 한다. 그런데 Q가 정방행렬이 되어버리면 Q의 column space가 전체 공간과 같아져버리게 된다. 따라서 임의의 벡터 b는 전체 공간인 Q의 column space에 이미 존재하기 때문에 투영 자체가 의미가 없어져버린다. 그래서 정방행렬(square matrix)인 직교 행렬(orthogonal matrix)의 투영 행렬(projection matrix)이 단위 행렬이 되는 것이다. 

 

마지막으로 투영 행렬의 특성중 하나인 

를 확인해보자. 투영시킨 벡터를 다시 투영해도 그 결과는 같다는 것 말이다. 식 (16)을 기준으로 이 특성을 다시 써보면 아래와 같다. 

 

식 (18)의 밑줄 친 부분이 단위행렬이 되므로 결과는 P와 같다. 

 

이와 같이 기존의 임의의 행렬 A에 대한 해를 구하는 식은 Q를 이용할 경우 훨씬 간단해진다. Lecture 15-(1)에서 배웠던 overdetermined case의 해를 구하는 식을 Q를 이용하여 정리하면 아래와 같이 간단하게 정리된다. 

 

 

앞의 Q transpose Q가 단위 행렬이 되어 사라지고 뒤의 식만 남게된다. 결과적으로 Q를 이용할 경우 해(solution) x hat의 각 원소들은 Q transpose와 b의 내적(dot product)연산에 의해 간단히 정의된다. 

 

 

 

3. 마치며..(continue)

 

이번 강의에선 그람-슈미트 과정을 배우기에 앞서 필요한 선행 지식인 직교행렬에 관해 공부하였다. 직교행렬(orthogonal matrix)은 정규직교벡터(orthonormal vector)들로 이루어진 행렬이며 계산을 간단하게 해주는 특징이 있다는 것을 공부하였다. 또한 실제 계산에 있어서 정규화(normalized)된 직교(orthogonal) 벡터들을 이용하기 때문에 계산 결과값이나 overflow, underflow와 같은 문제에 있어서 훨씬 좋은 성능을 보인다. 

 

그러나 여기서 어떤 사람들은 이런 의문이 들수도 있을 것이다. A대신 Q를 이용해서 식을 만들면 좋은건 알겠는데, 대체 A랑 Q랑 무슨 관계지? Q가 좋긴 하지만 A대신 사용하게 되면 원래 식과는 완전히 달라지는거 아냐? 

이후 과정에서 더 자세히 설명하긴 하겠지만, A와 Q는 같은 column space를 공유하는 행렬이다. 즉 A의 column vector들을 기반으로 A와 똑같은 column space, 혹은 부분 공간(subspace)을 이루는 행렬 Q를 만드는 것이다(※이때 A는 반드시 독립이어야 함). 다시 말하면 원래 A가 가지고 있던 column vector들은 column space의 기저(basis)이긴 하지만, 최적의 기저는 아닐 가능성이 크다. 원래의 행렬 A의 column space의 기저(basis)를 보다 최적화된 기저로 만들어준다! 정도로 생각하면 될 것 같다. 

 

원래 그람-슈미트 과정(Gram-Schmidt Process)까지 이번 포스팅에서 다루려고 했으나, 내용이 너무 길어질 것 같아서 나누어서 하겠습니다. 다음 강의(17-(2))에서는 직교행렬에 이어 그람-슈미트 과정을 다루도록 하겠습니다. 

 

+ Recent posts