본문 바로가기

수학/선형대수

PCA(Principle Component Analysis)

PCA(Principle Component Analysis)


주요 키워드

  • 공분산 행렬(Covariance Matrix)
  • 고유값, 고유벡터(Eigen Value, Eigen Vector)
  • 선형변환(Linear Transformation)
  • 투영(Projection)
  • 대칭행렬(Symmetric Matrix)
  • 직교(Orthogonal)
  • 라그랑주 승수법(Lagrange multiplier method)

이거 왜 쓰는거지? 차원을 왜 줄여?


간단하게 말해 답은 "차원의 저주때문에"라고 할 수 있다.

위 그림을 보자.

좌측의 1차원으로 표현된 데이터들이

우측의 2차원으로 표현되면서 빈공간(sparsity)이 발행한다.

즉, 데이터를 표현할 수 있는 공간은 넓어졌는데, 쓸모없는 공간이 많아졌다.


반대로 우측의 그림부터보자.

2차원으로 표현된 데이터를

좌측의 1차원으로 표현되는 이과정이 PCA라 할 수 있다.



원래 데이터의 분산은 최대한 유지시켜줘야해!!?


데이터의 분산을 최대한 유지시킨다.

다시말해, 변환된 데이터의 분산을 최대로 해야하는 이유는 정보손실을 최소화하기 위한 것이다. 

상식적으로 생각해보면 당연하다.


출처 : https://wikidocs.net/7646


PC1으로 데이터를 내려보면 어느정도 퍼짐의 정도(분산)가 유지된다.

하지만 PC2로 데이터를 내리면...원래 데이터의 퍼짐정도가 파괴되면서 데이터의 특성이 손실된다.



그래서 PCA는...

원래 데이터의 분산을 최대한 보존하고, 차원을 줄일 새로운 기저축을 찾는 거야!!


데이터의 차원을 줄이는 문제이기 때문에, 이는 곧 '선형변환(Linear Transformation)'문제가 된다.






  u,v   w Projection     .


출처 : ratsgo.github.io




분산을 최대로 보존해주는 기저축은 어떻게 찾지?


이 문제는 $Var[$Xa$]$를 최대로 하는 a(기저)를 찾는 문제가 된다.



결국, $Var[$Xa$]$를 최대로 하는 a(기저)는 고유벡터가 된다.(  값 =   산)



정리해보면.....


즉 원 데이터의 공분산행렬은 대칭행렬이기 때문에 고유벡터들은 서로 직교한다. 

이 공분산행렬을 고유분해하여 고유값/고유벡터를 구하고 각 고유값의 크기를 비교한다. 

가장 큰 고유값이 가장 큰 분산을 의미한다.(분산을 가장많이 보존할 수 있다.) 

PCA의 주성분 갯수를 정하고 그 갯수만큼 고유값을 큰 순서대로 고르고 해당 고유값의 고유벡터들로 선형변환을 실시하면 된다.:)



PCA in Python


1) iris data


# iris데이터에서 꽃입의 "길이" 와 "폭" 만을 가져와 비교
iris = load_iris()
X = iris.data[:40,:2]
length = iris.data[:40,:1]
width = iris.data[:40,1:2]

# 2차원의 iris data plt.scatter(length, width) plt.plot(X[:, 0], X[:, 1], "o-", markersize=8) plt.xlabel("length") plt.ylabel("width") plt.title("PCA") plt.show()

# pca를 통한 차원 축소
pca1 = PCA(n_components=1)
X_low = pca1.fit_transform(X)

# 1차원의 iris data
plt.scatter(X_low, [0]*40)
plt.xlabel("Principle Componet")
plt.show()

2. Image data(Olevetti faces)


faces_all = fetch_olivetti_faces()
K = 20
faces = faces_all.images[faces_all.target == K]

N = 2
M = 5
fig = plt.figure(figsize=(10, 5))
plt.subplots_adjust()
for i in range(N):
    for j in range(M):
        k = i * M + j
        ax = fig.add_subplot(N, M, k+1) # plot을 위치시킴
        ax.imshow(faces[k], cmap=plt.cm.bone) # image를 나타냄
        ax.grid(False) # grid 삭제
        ax.xaxis.set_ticks([]) # plot의 숫자 값을 삭제
        ax.yaxis.set_ticks([])
       
plt.tight_layout() # 위열과 아래열의 간격을 좁힘
plt.suptitle("Olivetti face images")
plt.show()

PCA 적용전 원래 데이터


# 주성분이 2개인 PCA분석
pca3 = PCA(n_components=2)
X3 = faces_all.data[faces_all.target == K]
W3 = pca3.fit_transform(X3)
X32 = pca3.inverse_transform(W3)


N = 2
M = 5
fig = plt.figure(figsize=(10, 5))
plt.subplots_adjust(top=1, bottom=0, hspace=0, wspace=0.05)
for i in range(N):
    for j in range(M):
        k = i * M + j
        ax = fig.add_subplot(N, M, k+1)
        ax.imshow(X32[k].reshape(64, 64), cmap=plt.cm.bone)
        ax.grid(False)
        ax.xaxis.set_ticks([])
        ax.yaxis.set_ticks([])
plt.tight_layout()
plt.show()


'수학 > 선형대수' 카테고리의 다른 글

벡터와 행렬 기초 정리(1)  (0) 2018.10.26