1 포켓몬 데이터 1

초딩에게 인기가 많은 포켓몬 캐릭터를 군집으로 묶어낸다. 주성분 분석을 통해 전처리하고 나서 계층적 군집화 및 k-평균 군집화 통계분석을 수행하고, 계층적 군집화와 평균 군집화 결과를 비교해보자.

캐글 포켓몬 데이터가 공개되어 721종류 포켓몬에 대한 데이터와 포켓몬 유형에 대한 정보가 담겨있다.

각 포켓몬에 대한 데이터 원본은 http://pokemondb.net/pokedex에서 확인한다.

1.1 포켓몬 데이터 불러오기

포켓몬 데이터를 캐글에서 다운로드 받아 불러온다. “Shuckle” 포켓몬은 이상점에 해당되니 대상에서 제거하고, 주성분분석과 군집분석을 위해 필요한 칼럼만 뽑아낸다.

# 0. 환경설정 --------------------------------------------
library(tidyverse)
library(janitor)

# 1. 포켓몬 데이터 ---------------------------------------
pkmon_dat <- read_csv("data/Pokemon.csv") 
Parsed with column specification:
cols(
  `#` = col_double(),
  Name = col_character(),
  `Type 1` = col_character(),
  `Type 2` = col_character(),
  Total = col_double(),
  HP = col_double(),
  Attack = col_double(),
  Defense = col_double(),
  `Sp. Atk` = col_double(),
  `Sp. Def` = col_double(),
  Speed = col_double(),
  Generation = col_double(),
  Legendary = col_logical()
)
pkmon_df <- pkmon_dat %>%  
  clean_names() %>% 
  dplyr::filter(name != "Shuckle") %>% 
  select(-number, -type_2) %>% 
  mutate_if(is.character, as.factor) %>% 
  mutate(generation = factor(generation)) %>% 
  as.data.frame() %>% 
  column_to_rownames(var="name")

# pkmon_legend <- ifelse(pkmon_dat$Legendary =="True", TRUE, FALSE)

pkmon_df %>% 
  sample_n(100) %>% 
  DT::datatable()

1.2 데이터 전처리

군집분석 및 주성분분석을 위해 가장 먼저 척도조정이 필수적이다. 척도조정이 이루어지지 않는 경우 특정변수에 왜곡이 발생할 우려가 있다.

이런 왜곡을 잡아내는데 scale 함수를 활용한다. colMeans, apply 함수에 sd 값을 통해 척도조정이 잘 이루어졌는지 확인한다.

# 2. 데이터 전처리 ---------------------------------------
## 2.1. 척도 조정 ----------------------------------------
# 척도조정되지 않은 원본
pkmon_df %>% 
  select(total:speed) %>% 
  gather(variable, value) %>% 
  group_by(variable) %>% 
  summarise_all(funs(mean, sd))
# A tibble: 7 x 3
  variable  mean    sd
  <chr>    <dbl> <dbl>
1 attack    79.1  32.4
2 defense   73.6  30.7
3 hp        69.3  25.5
4 sp_atk    72.9  32.7
5 sp_def    71.7  27.3
6 speed     68.4  29.0
7 total    435.  120. 
# colMeans(pkmon_df)
# apply(pkmon_df, 2, sd)

# 척도조정
pkmon_scaled_df <- pkmon_df %>% 
  mutate_if(is.integer, scale)

rownames(pkmon_scaled_df) <- rownames(pkmon_df)

# 척도조정한 원본
# colMeans(pkmon_scaled_df)
# apply(pkmon_scaled_df, 2, sd)

pkmon_scaled_df %>% 
  select(total:speed) %>% 
  gather(variable, value) %>% 
  group_by(variable) %>% 
  summarise_all(funs(mean, sd))
# A tibble: 7 x 3
  variable  mean    sd
  <chr>    <dbl> <dbl>
1 attack    79.1  32.4
2 defense   73.6  30.7
3 hp        69.3  25.5
4 sp_atk    72.9  32.7
5 sp_def    71.7  27.3
6 speed     68.4  29.0
7 total    435.  120. 

2 차원축소

차원(dimension)은 데이터셋의 단순히 칼럼(변수)라고 볼 수 있고, 차원수(Dimensionality)는 데이터셋을 규정하는 차원의 수라고 정의하자. 데이터셋을 규정하는 잠재된 내재 차원은 측정된 칼럼 혹은 변수를 통해 데이터로 발현된 것으로 가정한다. 따라서, 데이터셋에 잠재된 차원을 찾아내는 방법이 필요하고 이에 더하여 차원의 저주(Curse of dimensionality)로 인하여 차원이 증가할수록 필요로하는 관측점의 수가 기하급수적으로 증가하게 되어 차원을 축약하는 것이 반듯이 필요하다. 그리고 자료형에 따라 다양한 차원축소방법이 개발되어 활용되고 있다.

  • 주성분분석(Principal Component Analysis)
  • N-NMF(Non-Negative Matrix Factorization)
  • 요인분석(Factor Analysis)

차원축소 기법

2.1 탐색적 데이터 분석

차원축소기법은 변수간의 상관관계를 바탕으로 이를 축약해 나가는 것이 기본이라 상관관계를 통해 사전적으로 파악하는 것이 필요하다.

2.1.1 상관계수 2

corrr 팩키지를 통해서 상관계수를 데이터프레임으로 변환시켜 후속/연결 작업을 수월히 수행할 수 있다.

library(corrr)

pkmon_scaled_df %>% 
  select_if(is.numeric) %>% 
  correlate() %>% # (2)
  shave(upper = TRUE) %>% # (3)
  stretch(na.rm = TRUE) %>% 
  arrange(-r) %>% 
  DT::datatable() %>% 
    DT::formatRound("r", digits = 2)

Correlation method: 'pearson'
Missing treated using: 'pairwise.complete.obs'

2.1.2 상관계수 시각화

ggcorrplot은 ggplot2 기반이라 corrplot이 갖는 기능을 그대로 옮겨왔다.

library(ggcorrplot)

pkmon_df %>% 
  select_if(is.numeric) %>% 
  cor() %>% 
  ggcorrplot(hc.order = TRUE, type = "lower",
             outline.col = "white",
             lab = TRUE)

2.2 차원축소 주성분 분석

차원축소를 개념적으로 추진하는 파이프라인은 상관관계를 제거하고, 주성분을 신규 차원으로 추출해서 데이터셋의 잠재된 차원 식별하여 시각화 도구로 커뮤니케이션하는 것으로 정의되지만, 실무적으로는 상관계수 행렬을 분해하여 좌표계를 바꾸고 차원수를 줄여 시각화 도구로 커뮤니케이션하게 되는 절차를 거치게 됩니다. 이제 데이터단으로 내려오게 되면, 중심화/표준화를 통해 데이터 전처리 작업을 수행하고 회전과 투영으로 좌표계를 변환하고 설명되는 분산을 최대화되는 차원을 선택하여 차원 축소작업을 마무리한다.

PCA ...

군집분석 등 후속분석을 위해 활용될 수 있는 변수가 많은 경우 차원을 축소할 필요가 있다. 이런 목적으로 Base R prcomp() 함수를 사용해서 주성분 분석을 수행했다. 물론 scale=TRUE, center=TRUE 인자를 넣어 척도를 조정한다.

주성분을 몇개까지 선택할 것인지에 대해서 설명되는 분산량을 누적한 누적 설명되는 분산량을 기준으로 80%, 90% 등 선정을 한다.

2.3 차원축소 주성분 분석 통계량

FactoMineR 팩키지 PCA() 함수를 사용해서 차원을 축소하려는 변수를 넣고, 부가변수도 지정한다. summary() 함수를 통해서 주성분분석 주요내용을 확인할 수 있다. 특히, PCA()함수에 범주형 변수는 quali.sup, 연속형 변수는 quanti.sup으로 지정한다.

## 2.2. PCA 주성분분석 ----------------------------------------
library(FactoMineR)
library(factoextra)
Welcome! Related Books: `Practical Guide To Cluster Analysis in R` at https://goo.gl/13EFCZ
pkmon_pca <- PCA(pkmon_scaled_df, quali.sup = c(1, 9:10), quanti.sup= 2, graph = FALSE)

summary(pkmon_pca)

Call:
PCA(X = pkmon_scaled_df, quanti.sup = 2, quali.sup = c(1, 9:10),  
     graph = FALSE) 


Eigenvalues
                       Dim.1   Dim.2   Dim.3   Dim.4   Dim.5   Dim.6
Variance               2.754   1.065   0.760   0.724   0.425   0.273
% of var.             45.897  17.755  12.664  12.060   7.081   4.544
Cumulative % of var.  45.897  63.652  76.315  88.375  95.456 100.000

Individuals (the 10 first)
                              Dist    Dim.1    ctr   cos2    Dim.2    ctr
Bulbasaur                 |  1.786 | -1.561  0.111  0.764 |  0.082  0.001
Ivysaur                   |  0.870 | -0.359  0.006  0.170 |  0.113  0.002
Venusaur                  |  1.485 |  1.297  0.076  0.763 |  0.124  0.002
VenusaurMega Venusaur     |  2.957 |  2.658  0.321  0.808 | -0.606  0.043
Charmander                |  1.979 | -1.774  0.143  0.803 |  0.744  0.065
Charmeleon                |  0.972 | -0.442  0.009  0.207 |  0.784  0.072
Charizard                 |  1.677 |  1.339  0.081  0.637 |  0.883  0.092
CharizardMega Charizard X |  2.926 |  2.646  0.318  0.818 |  0.359  0.015
CharizardMega Charizard Y |  3.376 |  2.805  0.358  0.690 |  1.167  0.160
Squirtle                  |  1.824 | -1.647  0.123  0.815 | -0.420  0.021
                            cos2    Dim.3    ctr   cos2  
Bulbasaur                  0.002 | -0.711  0.083  0.158 |
Ivysaur                    0.017 | -0.729  0.088  0.703 |
Venusaur                   0.007 | -0.697  0.080  0.220 |
VenusaurMega Venusaur      0.042 | -0.978  0.158  0.109 |
Charmander                 0.141 | -0.246  0.010  0.016 |
Charmeleon                 0.650 | -0.299  0.015  0.095 |
Charizard                  0.277 | -0.356  0.021  0.045 |
CharizardMega Charizard X  0.015 |  0.408  0.027  0.019 |
CharizardMega Charizard Y  0.119 | -1.095  0.198  0.105 |
Squirtle                   0.053 | -0.577  0.055  0.100 |

Variables
                             Dim.1    ctr   cos2    Dim.2    ctr   cos2  
hp                        |  0.644 15.047  0.414 | -0.146  1.997  0.021 |
attack                    |  0.725 19.081  0.525 | -0.049  0.230  0.002 |
defense                   |  0.609 13.462  0.371 | -0.635 37.823  0.403 |
sp_atk                    |  0.755 20.677  0.569 |  0.330 10.208  0.109 |
sp_def                    |  0.754 20.646  0.569 | -0.165  2.552  0.027 |
speed                     |  0.553 11.086  0.305 |  0.709 47.190  0.503 |
                           Dim.3    ctr   cos2  
hp                         0.199  5.232  0.040 |
attack                     0.594 46.508  0.353 |
defense                    0.001  0.000  0.000 |
sp_atk                    -0.281 10.359  0.079 |
sp_def                    -0.529 36.806  0.280 |
speed                      0.091  1.095  0.008 |

Supplementary continuous variable
                            Dim.1  cos2   Dim.2  cos2   Dim.3  cos2  
total                     | 0.998 0.997 | 0.017 0.000 | 0.029 0.001 |

Supplementary categories (the 10 first)
                              Dist    Dim.1   cos2 v.test    Dim.2   cos2
Bug                       |  0.879 | -0.820  0.871 -4.259 | -0.082  0.009
Dark                      |  0.432 |  0.124  0.082  0.424 |  0.284  0.431
Dragon                    |  1.645 |  1.599  0.945  5.560 |  0.100  0.004
Electric                  |  0.940 |  0.090  0.009  0.368 |  0.754  0.643
Fairy                     |  1.058 | -0.191  0.033 -0.479 | -0.331  0.098
Fighting                  |  0.896 | -0.264  0.087 -0.840 | -0.081  0.008
Fire                      |  0.596 |  0.318  0.284  1.427 |  0.405  0.461
Flying                    |  1.371 |  0.632  0.212  0.763 |  1.155  0.710
Ghost                     |  0.461 |  0.067  0.021  0.234 | -0.176  0.146
Grass                     |  0.345 | -0.176  0.258 -0.926 | -0.023  0.004
                          v.test    Dim.3   cos2 v.test  
Bug                       -0.681 |  0.109  0.015  1.075 |
Dark                       1.560 |  0.233  0.291  1.516 |
Dragon                     0.560 |  0.258  0.025  1.707 |
Electric                   4.979 | -0.452  0.231 -3.533 |
Fairy                     -1.337 | -0.744  0.494 -3.553 |
Fighting                  -0.416 |  0.720  0.646  4.362 |
Fire                       2.923 | -0.023  0.002 -0.198 |
Flying                     2.242 | -0.100  0.005 -0.229 |
Ghost                     -0.985 | -0.339  0.541 -2.246 |
Grass                     -0.193 | -0.182  0.279 -1.832 |

pkmon_pca$eig을 통해서 고유값을 추출하고, dimdesc() 함수를 통해서 주성분에 대한 각 변수 기여도를 살펴볼 수 있고, pkmon_pca$var$contrib을 통해 각 변수별로 주성분에 대한 관련성도 파악이 가능하다.

pkmon_pca$eig
       eigenvalue percentage of variance cumulative percentage of variance
comp 1  2.7537946              45.896577                          45.89658
comp 2  1.0653025              17.755042                          63.65162
comp 3  0.7598176              12.663627                          76.31525
comp 4  0.7235886              12.059811                          88.37506
comp 5  0.4248413               7.080689                          95.45575
comp 6  0.2726552               4.544254                         100.00000
dimdesc(pkmon_pca, axes = 1:2)
$Dim.1
$Dim.1$quanti
        correlation       p.value
total     0.9983910  0.000000e+00
sp_atk    0.7545876 5.629670e-148
sp_def    0.7540238 1.236759e-147
attack    0.7248889 3.833778e-131
hp        0.6437136  1.097311e-94
defense   0.6088737  3.183841e-82
speed     0.5525233  4.658120e-65

$Dim.1$quali
                  R2      p.value
legendary 0.25171693 3.666798e-52
type_1    0.09202881 1.861077e-09

$Dim.1$category
          Estimate      p.value
TRUE     1.5227691 3.666798e-52
Dragon   1.4940128 2.030520e-08
Psychic  0.4898765 4.942837e-03
4        0.3323494 1.544115e-02
Steel    0.5700855 3.155112e-02
Normal  -0.5588593 3.803328e-03
Bug     -0.9252577 1.872704e-05
FALSE   -1.5227691 3.666798e-52


$Dim.2
$Dim.2$quanti
        correlation       p.value
speed     0.7090250 4.972817e-123
sp_atk    0.3297705  1.008345e-21
hp       -0.1458601  3.493324e-05
sp_def   -0.1648874  2.791213e-06
defense  -0.6347632  2.485347e-91

$Dim.2$quali
                   R2      p.value
type_1    0.206333659 1.061580e-29
legendary 0.009020805 7.218897e-03

$Dim.2$category
           Estimate      p.value
Electric  0.7687146 5.338879e-07
Psychic   0.6142532 4.868946e-06
Fire      0.4199670 3.405883e-03
TRUE      0.1792962 7.218897e-03
1         0.2051997 9.881398e-03
Flying    1.1697393 2.489865e-02
Normal    0.2111912 4.474693e-02
FALSE    -0.1792962 7.218897e-03
Ground   -0.4725154 6.334686e-03
Rock     -0.9381406 1.854639e-10
Steel    -1.4543402 1.965111e-14
pkmon_pca$var$contrib
           Dim.1      Dim.2        Dim.3       Dim.4      Dim.5
hp      15.04714  1.9971006 5.232081e+00 68.05993636  3.7984233
attack  19.08145  0.2300026 4.650755e+01  4.19517859  4.3365493
defense 13.46241 37.8225191 2.286476e-04 20.48699204  0.7494368
sp_atk  20.67701 10.2082349 1.035945e+01  0.16723454 54.0013552
sp_def  20.64613  2.5521246 3.680590e+01  0.01465437 10.1754645
speed   11.08587 47.1900181 1.094799e+00  7.07600411 26.9387708

2.4 차원축소 주성분 분석 시각화

biplot을 통해 주성분분석 결과를 통해 변수들간에 연관성이 큰 변수를 이해하고 관측점들 관계도 동시에 시각화한다.

2.4.1 변수 및 관측점 대한 PCA 시각화

주성분과 변수에 대한 관련성, 주성분과 관측점에 대한 관련성을 시각화한다.

pca_var_g <- fviz_pca_var(pkmon_pca, select.var = list(cos2 = 0.5), repel = TRUE)
pca_ind_g <- fviz_pca_ind(pkmon_pca, select.ind = list(cos2 = 0.7), repel = TRUE)

cowplot::plot_grid(pca_var_g, pca_ind_g, ncol=2)

2.4.2 주성분에 대한 변수 기여도 시각화

주성분에 대한 변수 기여도 시각화한다.

pca_1_g <- fviz_cos2(pkmon_pca, choice = "var", axes = 1, top = 5)
pca_2_g <- fviz_cos2(pkmon_pca, choice = "var", axes = 2, top = 5)

cowplot::plot_grid(pca_1_g, pca_2_g, ncol=2)

2.4.3 biplot 시각화

주성분 평면에 변수와 관측점을 함께 시각화하고, 보조변수(pkmon_df$legendary)를 바탕으로 이를 시각화한다.

# fviz_pca_biplot(pkmon_pca)

fviz_pca_ind(pkmon_pca, habillage = pkmon_df$legendary, addEllipses = TRUE)