Chapter 2. 주성분 분석 예제
(1) 89구역 54식물종 분석 (단위: 그램)
- 참조: The R Book: R로 배우는 데이터 분석 기술 (Page 942-945)
pgdata <- read.table("data/pgfull.txt", header = T)
names(pgdata)
## [1] "AC" "AE" "AM" "AO" "AP" "AR" "AS"
## [8] "AU" "BH" "BM" "CC" "CF" "CM" "CN"
## [15] "CX" "CY" "DC" "DG" "ER" "FM" "FP"
## [22] "FR" "GV" "HI" "HL" "HP" "HS" "HR"
## [29] "KA" "LA" "LC" "LH" "LM" "LO" "LP"
## [36] "OR" "PL" "PP" "PS" "PT" "QR" "RA"
## [43] "RB" "RC" "SG" "SM" "SO" "TF" "TG"
## [50] "TO" "TP" "TR" "VC" "VK" "plot" "lime"
## [57] "species" "hay" "pH"
- 실험조건에 해당하는 55열(plot)과 공변량에 해당하는 56~58열(lime, species richness(종), hay biomass(건초량), pH(토양 산성도))는 그대로 둠
- 총 변수에서 1~54열까지만 별도로 추출하여 데이터를 만듬
pgdata2 <- pgdata[, 1:54]
head(pgdata2)
- 총 변수에서 1~54열까지만 별도로 추출하여 데이터를 만듬
- 54개의 식물종마다 분산은 유의하게 다르기 때문에 scale = TRUE 옵션을 사용함
require(graphics)
model <- prcomp(pgdata2, scale = TRUE)
summary(model)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6
## Standard deviation 3.0048 2.3358 1.9317 1.78562 1.73303 1.51187
## Proportion of Variance 0.1672 0.1010 0.0691 0.05904 0.05562 0.04233
## Cumulative Proportion 0.1672 0.2682 0.3373 0.39639 0.45201 0.49434
## PC7 PC8 PC9 PC10 PC11 PC12
## Standard deviation 1.50878 1.37586 1.32441 1.27318 1.21950 1.19792
## Proportion of Variance 0.04216 0.03506 0.03248 0.03002 0.02754 0.02657
## Cumulative Proportion 0.53649 0.57155 0.60403 0.63405 0.66159 0.68816
## PC13 PC14 PC15 PC16 PC17 PC18
## Standard deviation 1.17227 1.13551 1.09308 1.06783 1.00572 0.95504
## Proportion of Variance 0.02545 0.02388 0.02213 0.02112 0.01873 0.01689
## Cumulative Proportion 0.71361 0.73749 0.75961 0.78073 0.79946 0.81635
## PC19 PC20 PC21 PC22 PC23 PC24
## Standard deviation 0.91853 0.89466 0.86437 0.84970 0.76898 0.75135
## Proportion of Variance 0.01562 0.01482 0.01384 0.01337 0.01095 0.01045
## Cumulative Proportion 0.83198 0.84680 0.86063 0.87401 0.88496 0.89541
## PC25 PC26 PC27 PC28 PC29 PC30
## Standard deviation 0.74191 0.70653 0.69475 0.67325 0.62565 0.56800
## Proportion of Variance 0.01019 0.00924 0.00894 0.00839 0.00725 0.00597
## Cumulative Proportion 0.90560 0.91485 0.92379 0.93218 0.93943 0.94540
## PC31 PC32 PC33 PC34 PC35 PC36
## Standard deviation 0.56269 0.53857 0.52670 0.49524 0.48706 0.46638
## Proportion of Variance 0.00586 0.00537 0.00514 0.00454 0.00439 0.00403
## Cumulative Proportion 0.95127 0.95664 0.96177 0.96632 0.97071 0.97474
## PC37 PC38 PC39 PC40 PC41 PC42
## Standard deviation 0.44471 0.4025 0.37661 0.35794 0.34381 0.31452
## Proportion of Variance 0.00366 0.0030 0.00263 0.00237 0.00219 0.00183
## Cumulative Proportion 0.97840 0.9814 0.98403 0.98640 0.98859 0.99042
## PC43 PC44 PC45 PC46 PC47 PC48
## Standard deviation 0.29639 0.26849 0.25825 0.23467 0.22753 0.21756
## Proportion of Variance 0.00163 0.00133 0.00124 0.00102 0.00096 0.00088
## Cumulative Proportion 0.99205 0.99338 0.99462 0.99564 0.99660 0.99747
## PC49 PC50 PC51 PC52 PC53 PC54
## Standard deviation 0.19922 0.17755 0.16758 0.15581 0.11255 0.01721
## Proportion of Variance 0.00073 0.00058 0.00052 0.00045 0.00023 0.00001
## Cumulative Proportion 0.99821 0.99879 0.99931 0.99976 0.99999 1.00000
- Propertion of Variance: 분산비율, 각 주성분의 차지하는 비율을 말하며 클 수록 영향도가 그만큼 높다는 의미
- Cumulative Proportion: 분산의 누적 합계
- 일반적으로 전체 변화량의 90%가량을 설명하는 주성분을 선택하며, 여기서는 분산의 누적 합계를 볼 때 PC24까지의 성분 선택을 볼 수 있음
screeplot(model, main = "", col = "green", type = "lines", pch = 1, npcs = length(model$sdev))
- 이 그래프는 PCA에서 사용하는 스크리 플롯(scree plot)이라고 함
- 그래프가 완만해 지는 부분 이전까지만 활용하는 것이 바람직함
biplot(model)
- 각 개체에 대한 첫번째, 두번째 주성분 점수 및 행렬도(biplot)임
- 가까운 거리와 방향일수록 변수들의 상관성이 높아짐
- 그림 오른쪽에 AP, AE, HS 종은 PC1에 대한 강한 양의 부하량을 갖고 있고, 그림 왼쪽 LC, PS, LO는 강한 음의 부하량을 갖고 있음
- 그림 위쪽에 AC와 AO 종은 PC2에 대한 강한 양의 부하량을 갖고 있고, 그림 아래쪽 TF, PL, RA는 PC2에 강한 음의 부하량을 갖고 있음
yv <- predict(model)[, 1]
yv2 <- predict(model)[, 2]
par(mfrow = c(1,2))
plot(pgdata$hay, yv, pch = 16, xlab = "biomass", ylab = "PC 1", col = "red")
plot(pgdata$pH, yv2, pch = 16, xlab = "soil pH", ylab = "PC 2", col = "blue")

par(mfrow = c(1,1))
- 보다시피, PC1과 바이오매스 사이에, PC2와 흙의 pH 사이에 매우 강한 관계가 있음을 알 수 있음
- 첫 번째 주성분은 바이오매스가 증가하는 것(빛을 얻기 위한 경쟁 증가)과 연관이 있고, 두 번째 주성분은 흙의 pH가 감소하는 것(산도의 증가)와 연관이 있는 것으로 보임
(2) 라면
# 데이터 가져오기
lamen <- read.table(file = "data/lamen.csv", header = T, sep = ",")
row.names(lamen) <- lamen$라면
lamen2 <- lamen[, -1]
- 라면의 종류는 총 10개가 있고, 100명을 대상으로 면, 그릇, 국물에 대해 만족도를 조사했다고 가정해보자
- 각각의 값은 만족도의 평균이고, 소수점 이하는 절사함
- 면, 그릇, 국물이 맛에 끼치는 영향은 어느정도일까?
- 면, 그릇, 국물이 끼치는 영향을 수치화 해서 맛에 대한 방정식을 만든다면 어떤 모습일까?
- 표준점수 산출(평균 및 표준점수 산출)
- 각 변수에 대한 상관행렬을 구해서 고유치, 고유벡터를 구함(분산 기여율 확인)
# 1. 표준점수 구하기
round(scale(lamen2),2)
## 면 그릇 국물
## 쇠고기라면 -0.67 0.28 1.45
## 해물라면 -1.34 1.23 -1.31
## 얼큰라면 1.34 -0.66 0.76
## 떡라면 -0.67 -0.66 0.07
## 짬뽕라면 0.00 1.23 1.45
## 만두라면 0.67 -0.66 -0.62
## 치즈라면 0.67 0.28 0.07
## 된장라면 -1.34 -1.60 -1.31
## 볶음라면 0.00 -0.66 -0.62
## 김치라면 1.34 1.23 0.07
## attr(,"scaled:center")
## 면 그릇 국물
## 3.0 3.7 2.9
## attr(,"scaled:scale")
## 면 그릇 국물
## 1.490712 1.059350 1.449138
표준점수 = (x - mean(x)) / sd(x)
scale함수를 이용하여 표준점수를 구함
# 2. 상관행렬
round(cor(lamen2), 2)
## 면 그릇 국물
## 면 1.00 0.14 0.36
## 그릇 0.14 1.00 0.34
## 국물 0.36 0.34 1.00
# 주성분 분석 하기
lamen_pca <- prcomp(lamen2, scale = TRUE)
print(lamen_pca)
## Standard deviations (1, .., p=3):
## [1] 1.2532290 0.9271193 0.7548953
##
## Rotation (n x k) = (3 x 3):
## PC1 PC2 PC3
## 면 0.5430600 -0.68268084 0.4889097
## 그릇 0.5247543 0.73046473 0.4370975
## 국물 0.6555294 -0.01918737 -0.7549259
summary(lamen_pca)
## Importance of components:
## PC1 PC2 PC3
## Standard deviation 1.2532 0.9271 0.7549
## Proportion of Variance 0.5235 0.2865 0.1900
## Cumulative Proportion 0.5235 0.8100 1.0000
- 첫번째 주성분(PC1)의 누적 기여율은 0.524, 즉 52%에 해당함.
- PC1이 분석대상의 데이터가 가지고 있던 정보가 PC1 주성분에 집약되어 있는 크기를 설명함
# PC1 & PC2 스크리 플롯
screeplot(lamen_pca, main = "", col = "green", type = "lines", pch = 1, npcs = length(lamen_pca$sdev))
- 위 요약과 그래프를 통해서 알 수 있듯이 PC1 + PC2의 누적 기여율은 0.79 즉, 약 80%가 되며 성분 선택은 PC1과 PC2까지만 하면 됨
# 각각에 대한 제1주성분, 제2주성분 점수 구하기
round(predict(lamen_pca), 2)
## PC1 PC2 PC3
## 쇠고기라면 0.73 0.64 -1.30
## 해물라면 -0.94 1.84 0.87
## 얼큰라면 0.88 -1.41 -0.21
## 떡라면 -0.67 -0.03 -0.67
## 짬뽕라면 1.59 0.87 -0.56
## 만두라면 -0.39 -0.93 0.51
## 치즈라면 0.56 -0.25 0.40
## 된장라면 -2.43 -0.23 -0.37
## 볶음라면 -0.75 -0.47 0.18
## 김치라면 1.42 -0.02 1.14
- 제1 주성분과 제2 주성분의 식을 세우면 다음과 같음
- z1 = 0.57 x u1 + 0.52 x u2 + 0.65 x u3
- z2 = -0.68 x u1 + 0.73 x u2 + 0.02 x u3
- u1: 면의 표준점수 / u2: 그릇의 표준점수 / u3: 국물의 표준점수
- 위의 식을 기준으로 라면 종류에 대해 주성분 점수를 구할 수 있음
- 쇠고기라면의 주성분 점수를 구해보면 다음과 같음
- z1 = 0.73 = 0.57 x (-0.67) + 0.52 x (0.28) + 0.65 x (1.45) (위 표준점수 참조)
- z2 = 0.64 = -0.68 x (-0.67) + 0.73 x (0.28) + 0.02 x (1.45)
# 각각에 대한 제1주성분, 제2주성분 점수를 토대로 그래프 작성
biplot(lamen_pca)

print(lamen_pca)
## Standard deviations (1, .., p=3):
## [1] 1.2532290 0.9271193 0.7548953
##
## Rotation (n x k) = (3 x 3):
## PC1 PC2 PC3
## 면 0.5430600 -0.68268084 0.4889097
## 그릇 0.5247543 0.73046473 0.4370975
## 국물 0.6555294 -0.01918737 -0.7549259
- 라면에 대한 종합 평가는 다음과 같이 할 수 있음
- 종합평가 1위는 짬뽕라면
- 면, 그릇, 국물중에서 가장 많은 영향을 끼치는 건 국물임을 확인할 수 있음
- “해물라면”은 그릇 / “얼큰라면”은 면의 영향을 가장 많이 받음
(3) 범죄율(내장데이터 활용)
- 참조: Gorakala, S. and Usuelli, M. (2015). Building A Recommendation System with R, (Page 11-14)
- USArrests 데이터 세트는 미국 내 50개 주의 범죄 관련 통계임
- 변수구성은 10만명당 살인, 폭행, 강간, 도시 인구 비율을 가짐
data("USArrests")
str(USArrests)
## 'data.frame': 50 obs. of 4 variables:
## $ Murder : num 13.2 10 8.1 8.8 9 7.9 3.3 5.9 15.4 17.4 ...
## $ Assault : int 236 263 294 190 276 204 110 238 335 211 ...
## $ UrbanPop: int 58 48 80 50 91 78 77 72 80 60 ...
## $ Rape : num 21.2 44.5 31 19.5 40.6 38.7 11.1 15.8 31.9 25.8 ...
rownames(USArrests)
## [1] "Alabama" "Alaska" "Arizona" "Arkansas"
## [5] "California" "Colorado" "Connecticut" "Delaware"
## [9] "Florida" "Georgia" "Hawaii" "Idaho"
## [13] "Illinois" "Indiana" "Iowa" "Kansas"
## [17] "Kentucky" "Louisiana" "Maine" "Maryland"
## [21] "Massachusetts" "Michigan" "Minnesota" "Mississippi"
## [25] "Missouri" "Montana" "Nebraska" "Nevada"
## [29] "New Hampshire" "New Jersey" "New Mexico" "New York"
## [33] "North Carolina" "North Dakota" "Ohio" "Oklahoma"
## [37] "Oregon" "Pennsylvania" "Rhode Island" "South Carolina"
## [41] "South Dakota" "Tennessee" "Texas" "Utah"
## [45] "Vermont" "Virginia" "Washington" "West Virginia"
## [49] "Wisconsin" "Wyoming"
apply(USArrests, 2, var)
## Murder Assault UrbanPop Rape
## 18.97047 6945.16571 209.51878 87.72916
USArrests_pca <- prcomp(USArrests, scale = TRUE)
summary(USArrests_pca)
## Importance of components:
## PC1 PC2 PC3 PC4
## Standard deviation 1.5749 0.9949 0.59713 0.41645
## Proportion of Variance 0.6201 0.2474 0.08914 0.04336
## Cumulative Proportion 0.6201 0.8675 0.95664 1.00000
print(USArrests_pca)
## Standard deviations (1, .., p=4):
## [1] 1.5748783 0.9948694 0.5971291 0.4164494
##
## Rotation (n x k) = (4 x 4):
## PC1 PC2 PC3 PC4
## Murder -0.5358995 0.4181809 -0.3412327 0.64922780
## Assault -0.5831836 0.1879856 -0.2681484 -0.74340748
## UrbanPop -0.2781909 -0.8728062 -0.3780158 0.13387773
## Rape -0.5434321 -0.1673186 0.8177779 0.08902432
names(USArrests_pca)
## [1] "sdev" "rotation" "center" "scale" "x"
USArrests_pca$rotation <- -USArrests_pca$rotation
USArrests_pca$x <- -USArrests_pca$x
biplot(USArrests_pca)

- 빨간색 화살표는 로딩 백터로 표현함, 다시 말하면 주성분 벡터를 따라 각 변수들이 어떻게 변하는지를 나타냄
- PC1 좌표를 기준으로 보면 살인, 폭행, 강간이 같은 방향으로 인접해 있는 것을 확인할 수 있음
- PC2 좌표를 기준으로 보면 도시 인구 비율은 다른 3개와 방향이 다르므로 상관관계가 낮음
- 위 범죄 데이터를 가지고 다음과 같이 평가할 수 있음
(A1) 범죄율 관련 상위 그룹을 보려면 PC1을 보면 된다 - Florida, Nevada, California
(A2) 범죄율 관련 하위 그룹을 보려면 PC1을 보면 된다 - North Dakota
(B1) 인구기준 관련 상위 그룹을 보려면 PC2를 기준으로 보면 됨 - California
(B2) 인구기준 관련 하위 그룹을 보려면 PC2를 기준으로 보면 됨 - Mississipi
- 인구 및 범죄율 평균 그룹을 보려면 그래프의 가운데 지점을 보면 됨 - Virginia, Indiana 등
(4) 2018 러시아 월드컵 조별예선 1차전
library(tidyverse)
## ── Attaching packages ───────────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 2.2.1 ✔ purrr 0.2.4
## ✔ tibble 1.4.2 ✔ dplyr 0.7.5
## ✔ tidyr 0.8.1 ✔ stringr 1.3.1
## ✔ readr 1.1.1 ✔ forcats 0.3.0
## ── Conflicts ──────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
worldcup <- read.csv("data/worldcup2018.csv", encoding = "UTF-8")
worldcup %>% mutate(점유율... = 점유율... / 100)
row.names(worldcup) <- worldcup$국가
colnames(worldcup) <- c("countries", "Shots", "Shots on Target", "Goals", "Possession", "Fouls", "Yellow Cards", "Red Cards", "Offsides", "Corners", "results")
worldcup2 <- worldcup[, -1]
worldcup2
num_df <- worldcup2[, -10]
apply(num_df, 2, var)
## Shots Shots on Target Goals Possession
## 29.834677 5.136089 1.318548 166.258065
## Fouls Yellow Cards Red Cards Offsides
## 20.951613 1.157258 0.031250 1.539315
## Corners
## 5.802419
- 가장 편차가 심한 것은 슈팅수라는 걸 알 수 있음
worldcup_pca <- prcomp(num_df, scale = TRUE)
summary(worldcup_pca)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 1.8411 1.1511 1.1286 0.9857 0.90663 0.73638 0.63395
## Proportion of Variance 0.3766 0.1472 0.1415 0.1080 0.09133 0.06025 0.04465
## Cumulative Proportion 0.3766 0.5239 0.6654 0.7733 0.86468 0.92493 0.96958
## PC8 PC9
## Standard deviation 0.45337 0.26115
## Proportion of Variance 0.02284 0.00758
## Cumulative Proportion 0.99242 1.00000
print(worldcup_pca)
## Standard deviations (1, .., p=9):
## [1] 1.8411106 1.1511306 1.1286132 0.9856823 0.9066322 0.7363832 0.6339469
## [8] 0.4533684 0.2611491
##
## Rotation (n x k) = (9 x 9):
## PC1 PC2 PC3 PC4
## Shots -0.48564926 0.098305216 -0.11016563 0.14775959
## Shots on Target -0.48122841 -0.219373824 -0.10462454 0.07565115
## Goals -0.13307121 -0.603043170 -0.35181677 -0.38166724
## Possession -0.41126045 0.323992201 0.01457237 0.15136787
## Fouls 0.26821648 0.006400956 -0.65729795 0.06567950
## Yellow Cards 0.24531183 -0.068169394 -0.42815984 0.37986382
## Red Cards 0.09127927 -0.325020244 0.17956835 0.79642812
## Offsides -0.13898644 -0.594483484 0.26809715 0.01196885
## Corners -0.43122361 0.099208813 -0.36530471 0.14425872
## PC5 PC6 PC7 PC8
## Shots -0.01831012 -0.21654144 -0.48159878 -0.12165617
## Shots on Target -0.05776136 -0.34477183 -0.18395422 -0.31462918
## Goals 0.30739503 -0.14463316 0.40082269 -0.04911310
## Possession -0.14488888 0.31483971 0.61965200 -0.43665155
## Fouls 0.08896219 0.47844508 -0.31295365 -0.38995594
## Yellow Cards -0.60838818 -0.39471616 0.24445876 0.11817124
## Red Cards 0.45540887 0.03188842 0.08464713 -0.04393070
## Offsides -0.53309476 0.49180916 -0.15097839 0.03489779
## Corners 0.10585918 0.29427153 0.04400397 0.72384649
## PC9
## Shots 0.65310677
## Shots on Target -0.66976883
## Goals 0.26590355
## Possession 0.08955054
## Fouls -0.06953393
## Yellow Cards 0.08886009
## Red Cards 0.04447746
## Offsides 0.07193204
## Corners -0.16202999
# PC1 & PC2 스크리 플롯
screeplot(worldcup_pca, main = "", col = "green", type = "lines", pch = 1, npcs = length(worldcup_pca$sdev))

worldcup_pca$rotation <- -worldcup_pca$rotation
worldcup_pca$x <- -worldcup_pca$x
biplot(worldcup_pca)
- 변수들의 특징을 살펴보면 크게 3가지 그룹으로 나눌 수 있는 것을 볼 수 있음
- 그림 오른쪽을 보면 유효슈팅수, 코너킥수, 슈팅수, 점유율은 같은 방향으로 근접해 위치하고 있는 걸 볼 수 있고, PC1에 대해 강한 양의 부하량을 갖고 있음
- 그림 왼쪽을 보면 파울수, 옐로카드는 같은 방향으로 근접해 위치하고 있는 걸 볼 수 있고, PC1에 대해 강한 음의 부하량을 갖고 있음
- 그림 상단을 보면 골수, 오프사이드는 같은 방향으로 근접해 위치하고 있는 걸 볼 수 있고, PC2에 대해 강한 양의 부하량을 갖고 있음
- 타 국가에 비해 아르헨티나, 독일, 잉글랜드, 브라질, 스페인의 경우 유효슈팅수, 슈팅수, 점유율 등이 높았음
- 타 국가에 비해 호주, 파나마, 대한민국의 경우 타 국가에 비해 파울수 옐로카드수가 높았음
- 타 국가에 비해 러시아, 스페인의 경우 오프사이드와 골수 모두 높았음
library(tidyverse)
library(ggfortify)
autoplot(worldcup_pca, data = worldcup2, colour = 'results',
label = TRUE, label.size = 5,
loadings = TRUE, loadings.colour = 'black',
loadings.label = TRUE,
loadings.label.size = 10,
loadings.label.colour = "black") +
theme(legend.text = element_text(size = 16),
legend.title = element_text(size = 24),
axis.title = element_text(size = 14))

- 승리팀, 패배팀, 무승부팀 그룹별로 분석하면 다음과 같음
- 승리팀 그룹의 경우 상대적으로 점유율, 슈팅수 등이 그렇지 않은 국가에 비해 높음
- 패배팀 그룹의 경우 상대적으로 파울수, 옐로카드수가 타 국가에 비해 높았음
- PC1을 기준으로 볼 때 무승부의 경우 3팀 VS 3팀의 경우로 나눠지는 흥미로운 결과가 나왔는데 좀 더 깊게 해석을 하자면 공격적인 팀과 수비적인 팀으로 나눠서 진행이 된 것을 볼 수 있음