2014년 10월 5일 일요일

PCA (Principal Component Analysis), 주성분 분석

우리가 다루는 데이터들은 보통 3차원 공간에선 표현하기 힘든 고차원(high dimension)의 데이터인 경우가 많습니다. 예를 들어 40개의 관절을 가진 휴머노이드 로봇을 제어하기 위해선 40차원의 벡터 (또는 120차원의 벡터)를 다루어야 하고, 또 미스코리아의 얼굴 유사도 분석과 같이 이미지 파일을 분석할래도 픽셀 수(e.g. 64*64=4096) 길이의 벡터를 다루어야 하죠. 생각해보세요. 이렇게 긴 벡터의 데이터를 분석한다면 컴퓨터로서도 매우 힘들지 않을까요? 그래서 필요한 것이 바로 차원 축소의 방법입니다.

* PCA를 처음 접하시는 분이시라면 지난번 T-Robotics 글 "미스코리아 얼굴들을 다 똑같다? PCA의 마법!"을 먼저 읽어주시면 이해에 도움이 되실 것입니다.

미스코리아의 얼굴은 다 똑같다? PCA로 분석한 미스코리아 얼굴의 유사도 분석! T-Robotics 글에서 한번 확인해보시죠. (사진 출처 : Refining Open Minds 블로그)
PCA는 고차원(ex: (x1,···,x10))의 데이터를 저차원 (ex: (x1,x2,x3))으로 압축하는 대표적인 차원 축소(dimension reduction) 방법입니다. 예를 들어 10차원의 데이터들이 있다고 생각해보세요. 2차원이나 3차원이라면야 그래프를 보면서 '어디가 비슷하네', '이건 이렇게 굽어졌네' 분석을 할 수 있겠지만, 차원이 높으면 보기 쉽지 않겠죠? 이렇듯 PCA는 데이터의 특성을 눈으로 쉽게 파악할 수 있도록 도움을 줍니다. 또한 PCA는 연산 속도에도 도움을 주는데, 예를 들어 10차원 벡터의 계산 대신 2차원 벡터만 계산해도 된다면 연산 속도에 큰 이점을 얻을 수 있겠지요.

스프링 운동을 하는 물체가 있다. 어느 위치의 카메라로 찍어야 가장 좋을까? (출처)

쉽게 이해를 돕기 위해 그림과 같이 스프링 운동을 하는 물체를 생각해봅시다. 비록 이 물체는 3차원 공간 상에서 움직이고 있지만 (Y=f(x1,x2,x3)), 좌표계를 잘 설정한다면 하나의 변수(Y=f(x1))로도 이 물체의 운동을 잘 표현할 수 있을 것입니다. 예를 들어 이 물체가 (1,1,1)→(2,2,2)→(3,3,3)으로 움직인다고 생각해본다면, 이 것을 단지 √→ 2√→ 3√3 의 숫자 한개씩 만으로도 표현할 수 있을 것이란 말이죠.

그렇다면 우리는 어떠한 좌표계를 잡아야 이렇듯 3차원을 단 1차원 운동으로 표현할 수 있을까요? 운동을 가장 잘 표현하는 축, 이것이 바로 PCA에서 말하는 Principal Component (주성분) 입니다. 그렇다면 어떤 축이 "운동을 가장 잘 표현하는 축"일까요? PCA에서는 데이터를 가장 넓게 펼치는 축, 그러니까 위의 예제에서는 x축을 PC라고 설정합니다. 통계학적인 표현으로는 "가장 큰 분산을 가지는 축"이 바로 PC가 되는 것이죠.

이렇듯 데이터를 가장 넓게 펼치는 축, 즉 분산이 가장 큰 축이 principal component (PC)이다. (출처)

그럼 이 축은 어떻게 찾아낼까요? 일단 먼저 데이터들의 분포를 보려면 각 데이터들의 상관관계를 나타내는 공분산(covariance) 행렬을 살펴볼 필요가 있습니다. 혹시 기억나지 않으시는 분들을 위해 평균분산, 공분산부터 짚어볼까요?


분산은 '데이터가 평균으로부터 얼마나 떨어져 있는가'를 나타내는 지표고요, 분산이 단지 평균점과 다른 점들의 관계를 나타낸다면 공분산은 점들의 그룹과 다른 점들의 그룹과의 관계를 나타내는 지표입니다. 예를 들어 평균이 0인 점들 A와 B의 공분산은 어떻게 되는지 살펴볼까요?


이것들을 여러 점들의 그룹 A와 B가 아닌, 행벡터 ab의 관계로 보자면 다음과 같이 표현할 수 있을 것이고요, 나아가 x1,x2, ···, xn의 행벡터들과 x1,x2···xn 행벡터들의 관계로 확장하자면 공분산 행렬은 다음과 같이 표현할 수 있습니다.


살펴보시면 아시겠지만 대각선의 값들은 각 행벡터들의 분산을 나타내고, 그 외의 값들은 벡터와 벡터들의 공분산을 나타내죠.

공분산을 왜 이야기 했느냐? 우리의 목적이 바로 축을 잘잘 회전시켜서 분산이 최대가 되도록 하는 것이기 때문이죠. 즉, 우리는 원래의 데이터 X에 어떠한 회전행렬 P를 곱해서 PX가 최대의 분산들을 갖도록 만들 것입니다. 최대의 분산을 갖는다는건 다른 말로 각 벡터들이 독립적인 역할을 잘 수행하여 서로 간의 연관성을 최소로 만든다는 것과 일맥상통하고, 이는 곧 공분산행렬을 대각행렬로(off-diagonal term이 0인 행렬) 만드는 과정이지요. Y=PX라고 하였을 때, Y에 대한 공분산 행렬은


인데요, 이 모습은 왠지 eigenvector를 이용한 대각행렬 만들기와 비슷하지 않나요? 대부분의 분들이 기억 못하시리라 믿고(ㅎㅎ) 대각화과정을 적어보면 다음과 같습니다.


eigenvector는 Ax = lx 를 만족하는 x인데요, 이 뜻 자체가 선형변환 A로도 방향이 유지되는 벡터 x란 뜻을 가지고 있습니다. 결국 이러한 독립된 방향들(eigenvector)을 모으면 결국 A를 다시 만들 수도 있다는 것이지요. (참고로 여기선 여러 eigenvector 중 orthonormal한 eigenvector들을 택함으로써 E-1=ET가 되었습니다)

이제 거의 다 왔습니다! 우리의 질문이 뭐였죠? 어떻게 하면 X를 가장 분산이 큰 축들(PCs)로 나타낼 수 있을까, 그리고 그렇게 변환하는 Y=PX의 P를 어떻게 찾아낼 수 있을까였죠? 그리고 이것은 CY를 대각행렬로 만드는 과정과 같았습니다. 

그럼 위의 식에서 A를 CX, D를 CY로 설정하면 되겠네요! 우리가 구하던 P는 바로 ET(X의 공분산 CX의 eigenvector들로 이루어진 행렬)이었던 것입니다.


자 그럼 정리하겠습니다. 고차원의 벡터들을 저차원(예를들면 3차원)에서 표현하고 싶다, 그러시면 먼저 데이터들을 주욱 열들로 합치십시오. (1열에 1번 데이터, 2열에 2번 데이터, ..., 100번열에 100번 데이터, 이런 식으로요) 이 행렬을 Xold라고 하면,

1. Xold의 평균 u를 구한 후 Xold에서 평균 u를 빼 평균이 0인 X를 만든다.
2. X의 공분산 행렬을 구한다. C = 1/n * (X XT)
3. C에 대하여 크기가 1인 eigenvector 들을 구한 후 이들을 eigenvalue 순으로 행벡터로 나열한 행렬 P를 만든다. (20차원 데이터면 20X20 행렬이 만들어짐)
4. P행렬을 위에서부터 관심있는 차원까지만 자른다. 예를 들어 C의 eigen-value 20개 중에 3개까지만 크게 나왔다면, P의 4행부터는 지워버린다.
5. Y = PX 를 계산하여 차원을 줄인다. 예를들어 P를 3행까지만 남겼면 우리는 20차원 X에서 3차원으로 줄어든 Y를 얻게된다.
이제 이 3차원 데이터 Y를 가지고 씹고 뜯고 맛보고 즐기고 하시면 됩니다 ^^ 예를 들면 그래프를 그려서 데이터들의 특징을 살펴볼 수도 있고, 저차원 상에서 데이터를 분류하거나 또는 새로운 예측 해볼 수도 있죠. 이제 PCA에 대해 감이 좀 오시나요? 너무 많은 변수를 가진 데이터, 앞으로는 PCA로 visualize 해보시죠 :D

* Matlab Code


* 이 글은 Jonathon Shlens의 "A Tutorial on PCA"를 참고하여 작성하였습니다.