열렬히.뛰기

주성분분석 : 코드 (2)

수학 & 통계 > 다변량분석 > 다변량분석 : 코드 > 주성분분석 : 코드 (2)

자료 제작

이전 “주성분분석 : 코드(1)”의 4x4 공분산행렬에서 쓴 코드를 사용

r
library(MASS)
D = diag(c(1, 2, 0.4, 0.5))
data = c(1, 0.6, 0.1, 0.3,
         0.6, 1, 0.2, 0.4,
         0.1, 0.2, 1, 0.5,
         0.3, 0.4, 0.5, 1)
rr <- matrix(data, nrow=4, byrow=TRUE)
Sigma = D^{1/2} %*% rr %*% D^{1/2}
mu = rep(0, 4)
n = 100
d1 = mvrnorm(n, mu, Sigma)
d1 = scale(d1)
eeR = eigen(cov(d1))

패키지 (1) - prcomp

prcomp() 안에 표준화된 자료행렬(p1)을 넣으면 객체가 반환되며, 이 안에 여러가지 정보가 있다.

  • standard deviation : 고유값의 제곱근.
  • Rotation : 고유벡터들을 모은 행렬이라고 생각하면 된다.
    • 부호가 반대로 되어도 걱정할 필요가 전혀 없음.
r
> d1.pc = prcomp(d1)
> d1.pc
Standard deviations (1, .., p=3):
[1] 1.5748360 0.7094494 0.6470424

Rotation (n x k) = (3 x 3):
            PC1         PC2         PC3
[1,] -0.4312426  0.89865671  0.08028646
[2,] -0.9010111 -0.43358408  0.01356221
[3,] -0.0469987  0.06649039 -0.99667956

> plot(d1.pc)

summary()를 통해 주성분의 분산, 점수, 누적점수를 한번에 볼 수 있다.

r
> summary(d1.pc)
Importance of components:
                         PC1    PC2    PC3
Standard deviation     1.575 0.7094 0.6470
Proportion of Variance 0.729 0.1479 0.1231
Cumulative Proportion  0.729 0.8769 1.0000

이번에는 d1.pc의 구조를 str()로 보자.

r
> str(d1.pc)
# sdev, rotation, center, scale, x가 있다.

> d1.pc$sdev # 표준편차
[1] 1.5748360 0.7094494 0.6470424
> d1.pc$center # 평균값
[1] 0.03309963 0.02035148 0.05805797
> d1.pc$scale # 표준화
[1] FALSE

표준편차 = 고유값의 제곱근인가?

실제로 그런지 확인해보자.

r
> ## 표준편차 = 고유값의 제곱근인지 확인
> d1.pc$sdev # 표준편차
[1] 1.4213361 1.0536106 0.6983555 0.6180680
> sqrt(eigen(cor(d1))$values) # 고유값의 제곱근
[1] 1.4213361 1.0536106 0.6983555 0.6180680

자료의 축소

설명력이 작은 고유벡터를 제거해보자.

r
# 고유값들을 tmp에 담고, 그것들을 반올림한 것을 tmp2에 담는다.
tmp = eigen(cor(d1))$vectors
tmp2 = round(tmp,3); tmp2

# 고유값이 0.3보다 작으면 (= 설명력이 낮으면) 제거
tmp3 = matrix(as.character(tmp2),4)
tmp3[abs(tmp2 < 0.3)] = ''
as.data.frame(tmp3)

biplot으로 확인

scale에 따라 표준화 여부가 결정, 이때 biplot의 모양이 달라진다.

r
## biplot 그리기
biplot(d1.pc, pch=19, cex=0.6, scale=T, lwd=3) 
biplot(d1.pc, pch=19, cex=0.6, scale=F, lwd=3) # 
  • scale = T : 표준화 o -> 원
  • scale = F :표준화 x -> 타원

패키지 (2) - princomp

r
d1.pc2 = princomp(d1)
str(d1.pc2)

loadings 살펴보기

loadings = 고유벡터

r
> loadings(d1.pc2)

Loadings:
     Comp.1 Comp.2 Comp.3 Comp.4
[1,]  0.526  0.511         0.680
[2,]  0.573  0.344 -0.255 -0.698
[3,]  0.391 -0.670 -0.596  0.209
[4,]  0.492 -0.415  0.761       

               Comp.1 Comp.2 Comp.3 Comp.4
SS loadings      1.00   1.00   1.00   1.00
Proportion Var   0.25   0.25   0.25   0.25
Cumulative Var   0.25   0.50   0.75   1.00

객체 보기

아까 prcomp()의 결과와는 살짝 다른 것을 알 수 있음.

r
> d1.pc2
Call:
princomp(x = d1)

Standard deviations:
   Comp.1    Comp.2    Comp.3    Comp.4 
1.4392711 1.0276119 0.7250234 0.5539435 

 4  variables and  100 observations.

biplot 그리기

prcomp()로 biplot을 그렸을 때와 달리 방향이 반대로 나올 수 있으나, 그 결과는 같다.

r
biplot(d1.pc2, pch=19, cex=0.6, scale=F, lwd=3)

이상치 찾아내기

biplot을 그리다 보면 뭔가 이상한 부분을 찾을 때가 많다.

이런 경우, 대부분 자료를 이루는 모집단이 두 개 이상인 경우가 많다.

자료 제작 - 모집단 2개 섞기

먼저 공분산행렬과 평균벡터를 만든다.

r
library(MASS)
data = c(1, 0.6, 0.1, -0.1,
         0.6, 1, 0.2, -0.2,
         0.1, 0.2, 1, 0.7,
         -0.1, 0.2, 0.7, 1)
rr = matrix(data, nrow = 4, byrow=TRUE)
D = diag(c(1, 2, 0.4, 0.2))
Sigma = D^{1/2} %*% rr %*% D^{1/2}
nn = 10000
mm = 20
mu = rep(0, dim(rr)[1])
# mu2 = rep(7, dim(rr)[1])
mu2 = c(7, 0, 1, 2)

rbind()를 사용해 두 집단을 섞는다.

r
n1 = mvrnorm(nn - mm, mu, Sigma)
n2 = mvrnorm(mm, mu2, Sigma)

d1 = rbind(n1, n2)
d1 = scale(d1)

새로운 자료인 d1을 살펴보자.

r
class(d1)
R = cov(d1)
eeR = eigen(R)

cumsum(eeR$values) / sum(eeR$values) * 100
round(eeR$vectors, 2)

이상치 찾아내기

r
P = data.frame(d1 %*% eeR$vectors[, 1:2])
plot(P$X1, P$X2, pch=19, col="grey", cex=0.2,
     xlab="1st pc", ylab="2nd pc", bty="l")