본문 바로가기

통계로 본 세상

R을 이용한 라면맛에 대한 주성분분석(PCA)

개요: 주성분 분석(PCA, Primary Components Analysis)의 흐름

1. 주성분과 주성분 점수를 구한다. 
2. 분석 결과의 정도를 확인한다. 
3. 분석 결과를 검토한다. 

각 라면에 대하여 면발, 라면 그릇의 모양(크기), 국물맛에 대한 점수가 있다고 한다면, 
3개의 변수(면, 그릇, 국물)를 가지고 PCA 분석(맛에 대한 종합점수 구하기)을 해보자. 

1) 면, 그릇, 국물이 맛에 끼치는 영향은 어느 정도일까? 
    면, 그릇, 국물에 대한 표준화 작업을 진행한다. 
        => 평균과 표준편차를 구해서 표준점수를 산출한다. 
    각 변수에 대한 상관행렬을 구해서 고유치, 고유벡터를 구한다. 
        => 고유치가 크다 = 분산정도(분산 기여율)가 크다 = 점수에 큰 영향을 끼친다

2) 면, 그릇, 국물이 끼치는 영향을 수치화 해서 맛에 대한 방정식을 만든다면 어떤 모습일까? 
    큰 영향을 끼치는 고유치값 2개를 선정한다. 
        => 고유치가 큰 2개를 선정한다 = 해당 하는 고유벡터 2개를 선정한다
    주성분점수1 = 각 항목의 표준점수 * 고유벡터_1 = z1*ev1 + z2*ev2 + ... 
    주성분점수2 = 각 항목의 표준점수 * 고유벡터_2 = z1*ev1 + z2*ev2 + ... 


1. 데이터를 read.table()을 이용해서 로드한다. 
--------------------------------------------------
> data <- read.table("110707-ramen-data.txt", header=T)

> data
           면 그릇 국물
쇠고기라면  2    4    5   
해물라면    1    5    1   
얼큰라면    5    3    4   
떡라면      2    2    3   
짬뽕라면    3    5    5   
만두라면    4    3    2   
치즈라면    4    4    3   
된장라면    1    2    1   
볶음라면    3    3    2   
김치라면    5    5    3   

> mean(data)            # 평균
  면 그릇 국물  
 3.0  3.6  2.9

> round(sd(data), 2)    # 표준편차
  면 그릇 국물
1.49 1.17 1.45

=> 표준점수(Z)를 어떻게 구하지???
표준점수 = (x - mean(x)) / sd(x)

> scale(data)           # scale 함수를 이용한 표준화 (책과 일치)
                   면       그릇        국물
쇠고기라면 -0.6708204  0.3407771  1.44913767
해물라면   -1.3416408  1.1927199 -1.31112456
얼큰라면    1.3416408 -0.5111657  0.75907212
떡라면     -0.6708204 -1.3631084  0.06900656
짬뽕라면    0.0000000  1.1927199  1.44913767
만두라면    0.6708204 -0.5111657 -0.62105900
치즈라면    0.6708204  0.3407771  0.06900656
된장라면   -1.3416408 -1.3631084 -1.31112456
볶음라면    0.0000000 -0.5111657 -0.62105900
김치라면    1.3416408  1.1927199  0.06900656
attr(,"scaled:center")
  면 그릇 국물
 3.0  3.6  2.9
attr(,"scaled:scale")
      면     그릇     국물
1.490712 1.173788 1.449138


> (data - mean(data))/sd(data)      # 평균과 표준편차를 이용한 표준화 => 책과 다소 다르다!
                    면       그릇        국물
쇠고기라면 -0.67082039  0.3407771  1.44913767
해물라면   -2.21505115  1.4491377 -1.34164079
얼큰라면    1.44913767  0.0000000  0.34077710
떡라면     -0.67082039 -1.3631084  0.06900656
짬뽕라면   -0.51116565  1.4491377  1.34164079
만두라면    0.75907212  0.0000000 -1.36310840
치즈라면    0.67082039  0.3407771  0.06900656
된장라면   -2.21505115 -0.6210590 -1.34164079
볶음라면    0.06900656  0.0000000 -1.36310840
김치라면    1.34164079  1.1927199  0.06900656

2. 이제 각 변수를 표준화하고, 이에 대한 상관행렬을 구한다.
var: 분산, cov: 공분산, cor: 상관행렬
> help(cor)
---------------------------------------------------------------
> cor(data)
            면      그릇      국물
면   1.0000000 0.1905002 0.3600411
그릇 0.1905002 1.0000000 0.3004804
국물 0.3600411 0.3004804 1.0000000

> round(cor(data), 2)       # 상관행렬
       면 그릇 국물
면   1.00 0.19 0.36
그릇 0.19 1.00 0.30
국물 0.36 0.30 1.00


3. EigenValue, EigenVector 값을 구한다. 첫번째 주성분(PC1)의 기여율은 Cumulative Proportion이 0.524
즉, 52%의 기여율을 보인다. 이것은 PC1이 분석대상의 데이터가 가지고 있던 정보가 PC1 주성분에 어느정도
집약 되어 있는지에 대한 대략적인 크기가 된다.
prcomp: 주성분분석 수행
---------------------------------------------------------------------------------------------------------
> p1 = prcomp(data, scale=TRUE)
> print(p1)
Standard deviations:
[1] 1.2541347 0.9022241 0.7830312

Rotation:
           PC1       PC2        PC3
면   0.5715110 -0.604471  0.5549685
그릇 0.5221161  0.789607  0.3223595
국물 0.6330639 -0.105526 -0.7668731

> summary(p1)
Importance of components:
                          PC1    PC2    PC3
Standard deviation     1.2541 0.9022 0.7830
Proportion of Variance 0.5243 0.2713 0.2044
Cumulative Proportion  0.5243 0.7956 1.0000

# 또는
> a <- eigen(cor(data), 2)
> a
$values
[1] 1.5728539 0.8140083 0.6131378

$vectors        # PC2와 부호가 반대임을 주목하자
          [,1]      [,2]       [,3]
[1,] 0.5715110  0.604471  0.5549685
[2,] 0.5221161 -0.789607  0.3223595
[3,] 0.6330639  0.105526 -0.7668731


=> 분산정도가 PC1이 0.5243으로 가장 크다. 즉 주성분 1이 된다.
=> PC1 + PC2 의 누적 기여율은 0.79 즉, 약 80% 정도가 된다.
누적비율은 순차적으로 PC1 + PC2 + PC3의 분산 합이다.

여기서 PC1과 PC2를 기준으로 그래프를 그릴 수 있다.

    좌표
--------------------------
면  (0.57, -0.60)
그릇    (0.52, 0.79)
국물    (0.63, 00.11)

z1(제1주성분) = 0.57u1 + 0.52u2 + 0.63u3
z2(제2주성분) = -0.60u1 + 0.79u2 - 0.11u3

u1: 면의 표준점수
u2: 그릇의 표준점수
u3: 국물의 표준점수

고유벡터는 a1^2 + a2^2 + a3^2 = 1이 성립한다.
> 0.57^2 + 0.52^2 + 0.63^2
[1] 0.9922


4. 각각에 대한 제1주성분, 제2주성분 점수를 구한다.
-----------------------------------------------------
> predict(p1)
                  PC1        PC2          PC3
쇠고기라면  0.7119408  0.5216497 -1.373736133
해물라면   -0.9740499  1.8911205  0.645382316
얼큰라면    0.9804158 -1.2947047 -0.002322692
떡라면     -1.0513965 -0.6781104 -0.864614382
짬뽕라면    1.5401350  0.7888582 -0.726820118
만두라면   -0.2766766 -0.7435735  0.683778524
치즈라면    0.6049920 -0.1436935  0.429217649
된장라면   -2.3084890 -0.1269792 -0.178513165
볶음라면   -0.6600579 -0.3380821  0.311494336
김치라면    1.4331863  0.1235150  1.076133664

> round(predict(p1), 2)
             PC1   PC2   PC3
쇠고기라면  0.71  0.52 -1.37
해물라면   -0.97  1.89  0.65
얼큰라면    0.98 -1.29  0.00
떡라면     -1.05 -0.68 -0.86
짬뽕라면    1.54  0.79 -0.73
만두라면   -0.28 -0.74  0.68
치즈라면    0.60 -0.14  0.43
된장라면   -2.31 -0.13 -0.18
볶음라면   -0.66 -0.34  0.31
김치라면    1.43  0.12  1.08

쇠고기라면의 주성분점수 PC1:0.71, PC2:0.52를 계산해보자.
1) z1(제1주성분) 점수 = 0.71 = 0.57*(-0.67) + 0.52*(0.34) + 0.63*(1.45) = 0.7084
2) z2(제2주성분) 점수 = 0.52 = -0.60*(-0.67) + 0.79*(0.34) - 0.11*(1.45) = 0.5111

5. 제1주성분 점수와 제2주성분 점수를 토대로 그래프 작성
biplot: 주성분 분석의 결과로부터 행과 열의 행렬도(biplot)를 표현한다.
---------------------------------------------------------
> png("plot2.png")
> biplot(p1)
> dev.off()
null device
          1

결론:
1) 라면의 종합평가에서 1위는 짬뽕라면이고, 2위는 김치라면,
'라면의 종합평가'에 가장 영향을 끼치고 있는 변수는 '국물'이 된다.
2) 해물라면은 '그릇'의 평가 영향을 많이 받았고, 얼큰라면은 '면'의
평가 영향을 많이 받았다.

주성분분석에서는 '주성분분석의 대상인 변수의 선정'과 '제1주성분의 정의'는
분석자의 판단에 맡긴다.