### Load standardpackages
library(tidyverse) # Collection of all the good stuff like dplyr, ggplot2 ect.
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.5     ✓ purrr   0.3.4
✓ tibble  3.1.4     ✓ dplyr   1.0.7
✓ tidyr   1.1.3     ✓ stringr 1.4.0
✓ readr   2.0.1     ✓ forcats 0.5.1
── Conflicts ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(magrittr) # For extra-piping operators (eg. %<>%)

Attaching package: ‘magrittr’

The following object is masked from ‘package:purrr’:

    set_names

The following object is masked from ‘package:tidyr’:

    extract

Introduction: Machine Learning with Pokémon

Back to the teens. You will work on Pokemon data. No data munging needed.

Getting the data

data <- read_csv('https://sds-aau.github.io/SDS-master/00_data/pokemon.csv')
Rows: 800 Columns: 13
── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Name, Type1, Type2
dbl (9): Number, Total, HitPoints, Attack, Defense, SpecialAttack, SpecialDefense, Speed, Generation
lgl (1): Legendary

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

EDA & Unsupervised ML

1.Give a brief overview of data, what variables are there, how are the variables scaled and variation of the data columns.

data %>% head()
data %>% glimpse()
Rows: 800
Columns: 13
$ Number         <dbl> 1, 2, 3, 3, 4, 5, 6, 6, 6, 7, 8, 9, 9, 10, 11, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40…
$ Name           <chr> "Bulbasaur", "Ivysaur", "Venusaur", "VenusaurMega Venusaur", "Charmander", "Charmeleon", "Charizard", "CharizardMega Charizard X", "CharizardMega Charizard Y", "Squirtle…
$ Type1          <chr> "Grass", "Grass", "Grass", "Grass", "Fire", "Fire", "Fire", "Fire", "Fire", "Water", "Water", "Water", "Water", "Bug", "Bug", "Bug", "Bug", "Bug", "Bug", "Bug", "Normal"…
$ Type2          <chr> "Poison", "Poison", "Poison", "Poison", NA, NA, "Flying", "Dragon", "Flying", NA, NA, NA, NA, NA, NA, "Flying", "Poison", "Poison", "Poison", "Poison", "Flying", "Flying…
$ Total          <dbl> 318, 405, 525, 625, 309, 405, 534, 634, 634, 314, 405, 530, 630, 195, 205, 395, 195, 205, 395, 495, 251, 349, 479, 579, 253, 413, 262, 442, 288, 438, 320, 485, 300, 450,…
$ HitPoints      <dbl> 45, 60, 80, 80, 39, 58, 78, 78, 78, 44, 59, 79, 79, 45, 50, 60, 40, 45, 65, 65, 40, 63, 83, 83, 30, 55, 40, 65, 35, 60, 35, 60, 50, 75, 55, 70, 90, 46, 61, 81, 70, 95, 3…
$ Attack         <dbl> 49, 62, 82, 100, 52, 64, 84, 130, 104, 48, 63, 83, 103, 30, 20, 45, 35, 25, 90, 150, 45, 60, 80, 80, 56, 81, 60, 90, 60, 85, 55, 90, 75, 100, 47, 62, 92, 57, 72, 102, 45…
$ Defense        <dbl> 49, 63, 83, 123, 43, 58, 78, 111, 78, 65, 80, 100, 120, 35, 55, 50, 30, 50, 40, 40, 40, 55, 75, 80, 35, 60, 30, 65, 44, 69, 40, 55, 85, 110, 52, 67, 87, 40, 57, 77, 48, …
$ SpecialAttack  <dbl> 65, 80, 100, 122, 60, 80, 109, 130, 159, 50, 65, 85, 135, 20, 25, 90, 20, 25, 45, 15, 35, 50, 70, 135, 25, 50, 31, 61, 40, 65, 50, 90, 20, 45, 40, 55, 75, 40, 55, 85, 60…
$ SpecialDefense <dbl> 65, 80, 100, 120, 50, 65, 85, 85, 115, 64, 80, 105, 115, 20, 25, 80, 20, 25, 80, 80, 35, 50, 70, 80, 35, 70, 31, 61, 54, 79, 50, 80, 30, 55, 40, 55, 85, 40, 55, 75, 65, …
$ Speed          <dbl> 45, 60, 80, 80, 65, 80, 100, 100, 100, 43, 58, 78, 78, 45, 30, 70, 50, 35, 75, 145, 56, 71, 101, 121, 72, 97, 70, 100, 55, 80, 90, 110, 40, 65, 41, 56, 76, 50, 65, 85, 3…
$ Generation     <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ Legendary      <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, F…
library(skimr)
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
data %>% skim()
── Data Summary ────────────────────────
                           Values    
Name                       Piped data
Number of rows             800       
Number of columns          13        
_______________________              
Column type frequency:               
  character                3         
  logical                  1         
  numeric                  9         
________________________             
Group variables            None      

── Variable type: character ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  skim_variable n_missing complete_rate   min   max empty n_unique whitespace
1 Name                  0         1         3    25     0      800          0
2 Type1                 0         1         3     8     0       18          0
3 Type2               386         0.518     3     8     0       18          0

── Variable type: logical ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  skim_variable n_missing complete_rate   mean count            
1 Legendary             0             1 0.0812 FAL: 735, TRU: 65

── Variable type: numeric ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  skim_variable  n_missing complete_rate   mean     sd    p0   p25   p50   p75  p100 hist 
1 Number                 0             1 363.   208.       1 185.   364.  539.   721 ▇▇▇▇▇
2 Total                  0             1 435.   120.     180 330    450   515    780 ▃▆▇▂▁
3 HitPoints              0             1  69.3   25.5      1  50     65    80    255 ▃▇▁▁▁
4 Attack                 0             1  79.0   32.5      5  55     75   100    190 ▂▇▆▂▁
5 Defense                0             1  73.8   31.2      5  50     70    90    230 ▃▇▂▁▁
6 SpecialAttack          0             1  72.8   32.7     10  49.8   65    95    194 ▅▇▅▂▁
7 SpecialDefense         0             1  71.9   27.8     20  50     70    90    230 ▇▇▂▁▁
8 Speed                  0             1  68.3   29.1      5  45     65    90    180 ▃▇▆▁▁
9 Generation             0             1   3.32   1.66     1   2      3     5      6 ▇▅▃▅▂

We have 3 string variables, where one is the uniqu pokemon name, and two others it’s type. Our outcome variable legendary is categorical, TRUE if it is an legendary pokemon, FALSE otherwise. All other variables are numerical.

Lets briefly look at th categorical variables:

data %>% count(Type1, sort = TRUE)

We see most pokemon are water-pokemon. However, there is no super-sparse class, so we can work with that.

data %>% count(Type2, sort = TRUE)

We see most pokemons have an NA as Type2, probably meening they have no second type.

We directly see some things should be changed:

  1. We see an numeric Number variable, which is just their unique id, and not of value for the analysis, so we drop it.
  2. the missing values in Type2 probably indicate that the pokemon has no second type, should therefore not be treated as missing data
  3. The generation variable is numeric, but probably should be interpreted as categorical.

Lets do the necessary changes upfront before investigating further.

data %<>%
  select(-Number) %>%
  replace_na(list(Type2 = 'None')) %>%
  mutate(Generation = Generation %>% as.character()) %>%
  relocate(Name, Legendary)

We now can do some visualization. First my favorite standard one. Since we already know we later will be interested in legendary pokemon, we can already use the olor aestetic on this variable.

library(GGally)
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2
data %>% 
  select(-Name, -Type1, -Type2) %>%
  ggpairs(legend = 1,
          mapping = ggplot2::aes(colour=Legendary, alpha = 0.5), 
          lower = list(continuous = wrap("smooth", alpha = 0.3, size=0.1))) +
  theme(legend.position = "bottom")  

 plot: [1,1] [=>------------------------------------------------------------------------------------------------------------------------------------------------------------------]  1% est: 0s 
 plot: [1,2] [===>----------------------------------------------------------------------------------------------------------------------------------------------------------------]  2% est: 6s 
 plot: [1,3] [=====>--------------------------------------------------------------------------------------------------------------------------------------------------------------]  4% est: 8s 
 plot: [1,4] [=======>------------------------------------------------------------------------------------------------------------------------------------------------------------]  5% est: 7s 
 plot: [1,5] [=========>----------------------------------------------------------------------------------------------------------------------------------------------------------]  6% est: 7s 
 plot: [1,6] [===========>--------------------------------------------------------------------------------------------------------------------------------------------------------]  7% est: 7s 
 plot: [1,7] [=============>------------------------------------------------------------------------------------------------------------------------------------------------------]  9% est: 7s 
 plot: [1,8] [===============>----------------------------------------------------------------------------------------------------------------------------------------------------] 10% est: 7s 
 plot: [1,9] [=================>--------------------------------------------------------------------------------------------------------------------------------------------------] 11% est: 7s 
 plot: [2,1] [===================>------------------------------------------------------------------------------------------------------------------------------------------------] 12% est: 7s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [2,2] [=====================>----------------------------------------------------------------------------------------------------------------------------------------------] 14% est: 7s 
 plot: [2,3] [=======================>--------------------------------------------------------------------------------------------------------------------------------------------] 15% est: 7s 
 plot: [2,4] [=========================>------------------------------------------------------------------------------------------------------------------------------------------] 16% est: 7s 
 plot: [2,5] [===========================>----------------------------------------------------------------------------------------------------------------------------------------] 17% est: 7s 
 plot: [2,6] [=============================>--------------------------------------------------------------------------------------------------------------------------------------] 19% est: 7s 
 plot: [2,7] [===============================>------------------------------------------------------------------------------------------------------------------------------------] 20% est: 6s 
 plot: [2,8] [=================================>----------------------------------------------------------------------------------------------------------------------------------] 21% est: 6s 
 plot: [2,9] [===================================>--------------------------------------------------------------------------------------------------------------------------------] 22% est: 6s 
 plot: [3,1] [=====================================>------------------------------------------------------------------------------------------------------------------------------] 23% est: 7s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [3,2] [=======================================>----------------------------------------------------------------------------------------------------------------------------] 25% est: 7s 
 plot: [3,3] [==========================================>-------------------------------------------------------------------------------------------------------------------------] 26% est: 9s 
 plot: [3,4] [============================================>-----------------------------------------------------------------------------------------------------------------------] 27% est: 9s 
 plot: [3,5] [==============================================>---------------------------------------------------------------------------------------------------------------------] 28% est: 9s 
 plot: [3,6] [================================================>-------------------------------------------------------------------------------------------------------------------] 30% est: 8s 
 plot: [3,7] [==================================================>-----------------------------------------------------------------------------------------------------------------] 31% est: 8s 
 plot: [3,8] [====================================================>---------------------------------------------------------------------------------------------------------------] 32% est: 8s 
 plot: [3,9] [======================================================>-------------------------------------------------------------------------------------------------------------] 33% est: 7s 
 plot: [4,1] [========================================================>-----------------------------------------------------------------------------------------------------------] 35% est: 7s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [4,2] [==========================================================>---------------------------------------------------------------------------------------------------------] 36% est: 7s 
 plot: [4,3] [============================================================>-------------------------------------------------------------------------------------------------------] 37% est: 7s 
 plot: [4,4] [==============================================================>-----------------------------------------------------------------------------------------------------] 38% est: 7s 
 plot: [4,5] [================================================================>---------------------------------------------------------------------------------------------------] 40% est: 6s 
 plot: [4,6] [==================================================================>-------------------------------------------------------------------------------------------------] 41% est: 6s 
 plot: [4,7] [====================================================================>-----------------------------------------------------------------------------------------------] 42% est: 6s 
 plot: [4,8] [======================================================================>---------------------------------------------------------------------------------------------] 43% est: 6s 
 plot: [4,9] [========================================================================>-------------------------------------------------------------------------------------------] 44% est: 6s 
 plot: [5,1] [==========================================================================>-----------------------------------------------------------------------------------------] 46% est: 6s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [5,2] [============================================================================>---------------------------------------------------------------------------------------] 47% est: 5s 
 plot: [5,3] [==============================================================================>-------------------------------------------------------------------------------------] 48% est: 5s 
 plot: [5,4] [================================================================================>-----------------------------------------------------------------------------------] 49% est: 5s 
 plot: [5,5] [==================================================================================>---------------------------------------------------------------------------------] 51% est: 5s 
 plot: [5,6] [====================================================================================>-------------------------------------------------------------------------------] 52% est: 5s 
 plot: [5,7] [======================================================================================>-----------------------------------------------------------------------------] 53% est: 5s 
 plot: [5,8] [========================================================================================>---------------------------------------------------------------------------] 54% est: 4s 
 plot: [5,9] [==========================================================================================>-------------------------------------------------------------------------] 56% est: 4s 
 plot: [6,1] [============================================================================================>-----------------------------------------------------------------------] 57% est: 4s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [6,2] [==============================================================================================>---------------------------------------------------------------------] 58% est: 4s 
 plot: [6,3] [================================================================================================>-------------------------------------------------------------------] 59% est: 4s 
 plot: [6,4] [==================================================================================================>-----------------------------------------------------------------] 60% est: 4s 
 plot: [6,5] [====================================================================================================>---------------------------------------------------------------] 62% est: 4s 
 plot: [6,6] [======================================================================================================>-------------------------------------------------------------] 63% est: 4s 
 plot: [6,7] [========================================================================================================>-----------------------------------------------------------] 64% est: 3s 
 plot: [6,8] [==========================================================================================================>---------------------------------------------------------] 65% est: 3s 
 plot: [6,9] [============================================================================================================>-------------------------------------------------------] 67% est: 3s 
 plot: [7,1] [==============================================================================================================>-----------------------------------------------------] 68% est: 3s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [7,2] [================================================================================================================>---------------------------------------------------] 69% est: 3s 
 plot: [7,3] [==================================================================================================================>-------------------------------------------------] 70% est: 3s 
 plot: [7,4] [====================================================================================================================>-----------------------------------------------] 72% est: 3s 
 plot: [7,5] [======================================================================================================================>---------------------------------------------] 73% est: 3s 
 plot: [7,6] [========================================================================================================================>-------------------------------------------] 74% est: 2s 
 plot: [7,7] [===========================================================================================================================>----------------------------------------] 75% est: 2s 
 plot: [7,8] [=============================================================================================================================>--------------------------------------] 77% est: 2s 
 plot: [7,9] [===============================================================================================================================>------------------------------------] 78% est: 2s 
 plot: [8,1] [=================================================================================================================================>----------------------------------] 79% est: 2s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [8,2] [===================================================================================================================================>--------------------------------] 80% est: 2s 
 plot: [8,3] [=====================================================================================================================================>------------------------------] 81% est: 2s 
 plot: [8,4] [=======================================================================================================================================>----------------------------] 83% est: 2s 
 plot: [8,5] [=========================================================================================================================================>--------------------------] 84% est: 1s 
 plot: [8,6] [===========================================================================================================================================>------------------------] 85% est: 1s 
 plot: [8,7] [=============================================================================================================================================>----------------------] 86% est: 1s 
 plot: [8,8] [===============================================================================================================================================>--------------------] 88% est: 1s 
 plot: [8,9] [=================================================================================================================================================>------------------] 89% est: 1s 
 plot: [9,1] [===================================================================================================================================================>----------------] 90% est: 1s 
 plot: [9,2] [=====================================================================================================================================================>--------------] 91% est: 1s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [9,3] [=======================================================================================================================================================>------------] 93% est: 1s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [9,4] [=========================================================================================================================================================>----------] 94% est: 1s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [9,5] [===========================================================================================================================================================>--------] 95% est: 0s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [9,6] [=============================================================================================================================================================>------] 96% est: 0s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [9,7] [===============================================================================================================================================================>----] 98% est: 0s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [9,8] [=================================================================================================================================================================>--] 99% est: 0s `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

 plot: [9,9] [====================================================================================================================================================================]100% est: 0s 
                                                                                                                                                                                                

Long story short, we already see that legendary pokemon appear to be pretty much better in everything.

We can also zoom into the conditional distributions with a joyplot

library(ggridges) # install if necessary

data %>%
  gather(variable, value, -Legendary) %>% # Note: At one point do pivot_longer instead
  ggplot(aes(y = as.factor(variable), 
             fill =  as.factor(Legendary), 
             x = percent_rank(value)) ) +
  ggridges::geom_density_ridges(alpha = 0.75)
Picking joint bandwidth of 0.0477

2. Execute a PCA analysis on all numerical variables in the dataset. Hint: Don’t forget to scale them first. Use 4 components. What is the individuel and cumulative explained variance?

Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
res_pca <- data %>% 
  column_to_rownames('Name') %>%
  select_if(is_numeric) %>%
  PCA(scale.unit = TRUE, 
      graph = FALSE, 
      ncp = 4)
res_pca %>% 
  fviz_screeplot(addlabels = TRUE, 
                 ncp = 4)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     

res_pca$eig %>% as_tibble()

4 Components sem to capture about 90% of the variance.

BONUS: Some visualization:

res_pca %>%
  fviz_pca_var(alpha.var = "cos2",
               col.var = "contrib",
               gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
               repel = TRUE,
               ggtheme = theme_gray()) 

All variables pretty much point into the same direction, meaning that we mainly capture a scaling phenomenon, where variables tend to move jointly. However, we do see in the secomd component, variables seem to split between defensive and offensive attributes.

res_pca %>% 
  fviz_pca_biplot(alpha.ind = "cos2",
                  geom = "point",                   
                  habillage = data %>% pull(Legendary) %>% factor(), 
                  addEllipses = TRUE,
                  ggtheme = theme_gray()) 

We generally see again legendary pokemon to be more in the right quadrants indicating high values in their characteristics. However, there is a large grey-zone, where the 2d projection cannot really distinguist between legendary and non-legendary pokemons.

res_pca %>% 
  fviz_pca_biplot(alpha.ind = "cos2",
                  geom = "point",                   
                  habillage = data %>% pull(Type1) %>% factor(), 
                  addEllipses = TRUE,
                  ggtheme = theme_gray()) 

For Type1, we get a mess…

Use a different dimensionality reduction method (eg. UMAP/NMF) –do the findings differ?

We ill run a simple UMAP

library(uwot)
Loading required package: Matrix

Attaching package: ‘Matrix’

The following objects are masked from ‘package:tidyr’:

    expand, pack, unpack
res_umap <-data%>%
  select_if(is_numeric) %>%
  umap(n_neighbors = 15, 
       metric = "cosine", 
       min_dist = 0.01, 
       scale = TRUE) 
res_umap %>%
  as_tibble() %>%
  bind_cols(data %>% select(Legendary)) %>%
  ggplot(aes(x = V1, y = V2, col = Legendary)) + 
  geom_point(shape = 21, alpha = 0.5) 

Well, UMAP seems to do a better job in sepperation high and low performing pokemons in spacw. However, we also see that only somewhat helps us to distinguish between legendary and non-legendary ones.

res_umap %>%
  as_tibble() %>%
  bind_cols(data %>% select(Type1)) %>%
  ggplot(aes(x = V1, y = V2, col = Type1)) + 
  geom_point(shape = 21, alpha = 0.5) 

Same goes for types…

4. Perform a cluster analysis (KMeans) on all numerical variables (scaled & before PCA). Pick a realistic number of clusters (up to you where the large clusters remain mostly stable).

# We use the viz_nbclust() function of the factorextra package
data %>%
  select_if(is_numeric) %>% 
  scale() %>%
  fviz_nbclust(kmeans, method = "wss")  

Ok,we here settle for 2 (executive decision, since we want to identify 2 distinct classes).

res_km <- data %>% 
  column_to_rownames('Name') %>%
  select_if(is_numeric) %>%
  scale() %>% 
  kmeans(centers = 2, nstart = 20)  

5.Visualize the first 2 principal components and color the datapoints by cluster.

res_km %>% 
  fviz_cluster(data = data %>% select_if(is_numeric))  

6.Inspect the distribution of the variable “Type1” across clusters. Does the algorithm separate the different types of pokemon?

table(data$Type1, res_km$cluster)
          
            1  2
  Bug      24 45
  Dark     17 14
  Dragon   23  9
  Electric 25 19
  Fairy     8  9
  Fighting 15 12
  Fire     29 23
  Flying    3  1
  Ghost    19 13
  Grass    35 35
  Ground   16 16
  Ice      14 10
  Normal   43 55
  Poison   14 14
  Psychic  35 22
  Rock     24 20
  Steel    19  8
  Water    59 53

Well, not really. However, in case I would have selected more, for instance 4, clusters, I might have had a different picture.

data %>%
  bind_cols(cluster = res_km$cluster) %>%
  select_if(is_numeric) %>%
  group_by(cluster) %>%
  mutate(n = n()) %>%
  summarise_all(funs(mean)) %>%
  pivot_longer(-cluster) %>%
  pivot_wider(names_from = cluster, values_from = value)

As we already guessed, the 2 clusters are mainly formed by overall high or low attributes.

7.Perform a cluster analysis on all numerical variables scaled and AFTER dimensionality reduction and visualize the first 2 principal components.

Since we didnt specify which type of clustering, we cann also do hirarchical clustering now and use the HCPCA function for convenience.

res_hcpc <- res_pca %>% 
  HCPC(nb.clust = -1, #  self determined: higher relative loss of inertia
       graph = FALSE) 
res_hcpc %>%
  plot(choice = "3D.map")

Interestingly, here we would have 3 clusters, with one in the middle.

8.Again, inspect the distribution of the variable “Type 1” across clusters, does it differ from the distribution before dimensionality reduction?

table(data$Type1, res_hcpc$data.clust$clust)
          
            1  2  3
  Bug      39 21  9
  Dark     11 12  8
  Dragon    5  7 20
  Electric 16  9 19
  Fairy     8  6  3
  Fighting  9 13  5
  Fire     19 11 22
  Flying    1  0  3
  Ghost    13 12  7
  Grass    28 31 11
  Ground   14 13  5
  Ice       9  9  6
  Normal   43 46  9
  Poison   14 13  1
  Psychic  19 15 23
  Rock     16 20  8
  Steel     6 15  6
  Water    44 50 18

Well, not reall in most cases…

LS0tCnRpdGxlOiAnTWFjaGluZSBMZWFybmluZzogV29ya2Zsb3cgYW5kIEFwcGxpY2F0aW9ucycKYXV0aG9yOiAiRGFuaWVsIFMuIEhhaW4gKGRzaEBidXNpbmVzcy5hYXUuZGspIgpkYXRlOiAiVXBkYXRlZCBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVkLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDEKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgdGhlbWU6IGZsYXRseQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIyMgR2VuZXJpYyBwcmVhbWJsZQpybShsaXN0PWxzKCkpClN5cy5zZXRlbnYoTEFORyA9ICJlbiIpICMgRm9yIGVuZ2xpc2ggbGFuZ3VhZ2UKb3B0aW9ucyhzY2lwZW4gPSA1KSAjIFRvIGRlYWN0aXZhdGUgYW5ub3lpbmcgc2NpZW50aWZpYyBudW1iZXIgbm90YXRpb24KCiMjIyBLbml0ciBvcHRpb25zCmxpYnJhcnkoa25pdHIpICMgRm9yIGRpc3BsYXkgb2YgdGhlIG1hcmtkb3duCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICBtZXNzYWdlPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICBjb21tZW50PUZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduPSJjZW50ZXIiCiAgICAgICAgICAgICAgICAgICAgICkKYGBgCgpgYGB7cn0KIyMjIExvYWQgc3RhbmRhcmRwYWNrYWdlcwpsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBDb2xsZWN0aW9uIG9mIGFsbCB0aGUgZ29vZCBzdHVmZiBsaWtlIGRwbHlyLCBnZ3Bsb3QyIGVjdC4KbGlicmFyeShtYWdyaXR0cikgIyBGb3IgZXh0cmEtcGlwaW5nIG9wZXJhdG9ycyAoZWcuICU8PiUpCmBgYAoKIyBJbnRyb2R1Y3Rpb246IE1hY2hpbmUgTGVhcm5pbmcgd2l0aCBQb2vDqW1vbgoKQmFjayB0byB0aGUgdGVlbnMuIFlvdSB3aWxsIHdvcmsgb24gUG9rZW1vbiBkYXRhLiBObyBkYXRhIG11bmdpbmcgbmVlZGVkLgoKIyBHZXR0aW5nIHRoZSBkYXRhCgpgYGB7cn0KZGF0YSA8LSByZWFkX2NzdignaHR0cHM6Ly9zZHMtYWF1LmdpdGh1Yi5pby9TRFMtbWFzdGVyLzAwX2RhdGEvcG9rZW1vbi5jc3YnKQpgYGAKCiMgRURBICYgVW5zdXBlcnZpc2VkIE1MCgojIyAxLkdpdmUgYSBicmllZiBvdmVydmlldyBvZiBkYXRhLCB3aGF0IHZhcmlhYmxlcyBhcmUgdGhlcmUsIGhvdyBhcmUgdGhlIHZhcmlhYmxlcyBzY2FsZWQgYW5kIHZhcmlhdGlvbiBvZiB0aGUgZGF0YSBjb2x1bW5zLgoKYGBge3J9CmRhdGEgJT4lIGhlYWQoKQpgYGAKCmBgYHtyfQpkYXRhICU+JSBnbGltcHNlKCkKYGBgCgpgYGB7cn0KbGlicmFyeShza2ltcikKZGF0YSAlPiUgc2tpbSgpCmBgYAoKV2UgaGF2ZSAzIHN0cmluZyB2YXJpYWJsZXMsIHdoZXJlIG9uZSBpcyB0aGUgdW5pcXUgcG9rZW1vbiBuYW1lLCBhbmQgdHdvIG90aGVycyBpdCdzIHR5cGUuIE91ciBvdXRjb21lIHZhcmlhYmxlIGBsZWdlbmRhcnlgIGlzIGNhdGVnb3JpY2FsLCBgVFJVRWAgaWYgaXQgaXMgYW4gbGVnZW5kYXJ5IHBva2Vtb24sIGBGQUxTRWAgb3RoZXJ3aXNlLiBBbGwgb3RoZXIgdmFyaWFibGVzIGFyZSBudW1lcmljYWwuIAoKTGV0cyBicmllZmx5IGxvb2sgYXQgdGggY2F0ZWdvcmljYWwgdmFyaWFibGVzOgoKYGBge3J9CmRhdGEgJT4lIGNvdW50KFR5cGUxLCBzb3J0ID0gVFJVRSkKYGBgCgpXZSBzZWUgbW9zdCBwb2tlbW9uIGFyZSB3YXRlci1wb2tlbW9uLiBIb3dldmVyLCB0aGVyZSBpcyBubyBzdXBlci1zcGFyc2UgY2xhc3MsIHNvIHdlIGNhbiB3b3JrIHdpdGggdGhhdC4KCmBgYHtyfQpkYXRhICU+JSBjb3VudChUeXBlMiwgc29ydCA9IFRSVUUpCmBgYAoKV2Ugc2VlIG1vc3QgcG9rZW1vbnMgaGF2ZSBhbiBgTkFgIGFzIGBUeXBlMmAsIHByb2JhYmx5IG1lZW5pbmcgdGhleSBoYXZlIG5vIHNlY29uZCB0eXBlLgoKV2UgZGlyZWN0bHkgc2VlIHNvbWUgdGhpbmdzIHNob3VsZCBiZSBjaGFuZ2VkOgoKMS4gV2Ugc2VlIGFuIG51bWVyaWMgYE51bWJlcmAgdmFyaWFibGUsIHdoaWNoIGlzIGp1c3QgdGhlaXIgdW5pcXVlIGlkLCBhbmQgbm90IG9mIHZhbHVlIGZvciB0aGUgYW5hbHlzaXMsIHNvIHdlIGRyb3AgaXQuCjIuIHRoZSBtaXNzaW5nIHZhbHVlcyBpbiBgVHlwZTJgIHByb2JhYmx5IGluZGljYXRlIHRoYXQgdGhlIHBva2Vtb24gaGFzIG5vIHNlY29uZCB0eXBlLCBzaG91bGQgdGhlcmVmb3JlIG5vdCBiZSB0cmVhdGVkIGFzIG1pc3NpbmcgZGF0YQozLiBUaGUgYGdlbmVyYXRpb25gIHZhcmlhYmxlIGlzIG51bWVyaWMsIGJ1dCBwcm9iYWJseSBzaG91bGQgYmUgaW50ZXJwcmV0ZWQgYXMgY2F0ZWdvcmljYWwuCgpMZXRzIGRvIHRoZSBuZWNlc3NhcnkgY2hhbmdlcyB1cGZyb250IGJlZm9yZSBpbnZlc3RpZ2F0aW5nIGZ1cnRoZXIuCgpgYGB7cn0KZGF0YSAlPD4lCiAgc2VsZWN0KC1OdW1iZXIpICU+JQogIHJlcGxhY2VfbmEobGlzdChUeXBlMiA9ICdOb25lJykpICU+JQogIG11dGF0ZShHZW5lcmF0aW9uID0gR2VuZXJhdGlvbiAlPiUgYXMuY2hhcmFjdGVyKCkpICU+JQogIHJlbG9jYXRlKE5hbWUsIExlZ2VuZGFyeSkKYGBgCgpXZSBub3cgY2FuIGRvIHNvbWUgdmlzdWFsaXphdGlvbi4gRmlyc3QgbXkgZmF2b3JpdGUgc3RhbmRhcmQgb25lLiBTaW5jZSB3ZSBhbHJlYWR5IGtub3cgd2UgbGF0ZXIgd2lsbCBiZSBpbnRlcmVzdGVkIGluIGxlZ2VuZGFyeSBwb2tlbW9uLCB3ZSBjYW4gYWxyZWFkeSB1c2UgdGhlIG9sb3IgYWVzdGV0aWMgb24gdGhpcyB2YXJpYWJsZS4KCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTJ9CmxpYnJhcnkoR0dhbGx5KQpkYXRhICU+JSAKICBzZWxlY3QoLU5hbWUsIC1UeXBlMSwgLVR5cGUyKSAlPiUKICBnZ3BhaXJzKGxlZ2VuZCA9IDEsCiAgICAgICAgICBtYXBwaW5nID0gZ2dwbG90Mjo6YWVzKGNvbG91cj1MZWdlbmRhcnksIGFscGhhID0gMC41KSwgCiAgICAgICAgICBsb3dlciA9IGxpc3QoY29udGludW91cyA9IHdyYXAoInNtb290aCIsIGFscGhhID0gMC4zLCBzaXplPTAuMSkpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICAKYGBgCkxvbmcgc3Rvcnkgc2hvcnQsIHdlIGFscmVhZHkgc2VlIHRoYXQgbGVnZW5kYXJ5IHBva2Vtb24gYXBwZWFyIHRvIGJlIHByZXR0eSBtdWNoIGJldHRlciBpbiBldmVyeXRoaW5nLgoKV2UgY2FuIGFsc28gem9vbSBpbnRvIHRoZSBjb25kaXRpb25hbCBkaXN0cmlidXRpb25zIHdpdGggYSBqb3lwbG90CgpgYGB7cixmaWcuaGVpZ2h0PTUsZmlnLndpZHRoPTEyLjV9CmxpYnJhcnkoZ2dyaWRnZXMpICMgaW5zdGFsbCBpZiBuZWNlc3NhcnkKCmRhdGEgJT4lCiAgZ2F0aGVyKHZhcmlhYmxlLCB2YWx1ZSwgLUxlZ2VuZGFyeSkgJT4lICMgTm90ZTogQXQgb25lIHBvaW50IGRvIHBpdm90X2xvbmdlciBpbnN0ZWFkCiAgZ2dwbG90KGFlcyh5ID0gYXMuZmFjdG9yKHZhcmlhYmxlKSwgCiAgICAgICAgICAgICBmaWxsID0gIGFzLmZhY3RvcihMZWdlbmRhcnkpLCAKICAgICAgICAgICAgIHggPSBwZXJjZW50X3JhbmsodmFsdWUpKSApICsKICBnZ3JpZGdlczo6Z2VvbV9kZW5zaXR5X3JpZGdlcyhhbHBoYSA9IDAuNzUpCmBgYAoKIyMgMi4gRXhlY3V0ZSBhIFBDQSBhbmFseXNpcyBvbiBhbGwgbnVtZXJpY2FsIHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldC4gSGludDogRG9uJ3QgZm9yZ2V0IHRvIHNjYWxlIHRoZW0gZmlyc3QuIFVzZSA0IGNvbXBvbmVudHMuIFdoYXQgaXMgdGhlIGluZGl2aWR1ZWwgYW5kIGN1bXVsYXRpdmUgZXhwbGFpbmVkIHZhcmlhbmNlPyAKCmBgYHtyLHdhcm5pbmc9RkFMU0UsZWNobz1GQUxTRX0KIyBMb2FkIHBhY2thZ2VzCmxpYnJhcnkoRmFjdG9NaW5lUikKbGlicmFyeShmYWN0b2V4dHJhKQpgYGAKCmBgYHtyfQpyZXNfcGNhIDwtIGRhdGEgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygnTmFtZScpICU+JQogIHNlbGVjdF9pZihpc19udW1lcmljKSAlPiUKICBQQ0Eoc2NhbGUudW5pdCA9IFRSVUUsIAogICAgICBncmFwaCA9IEZBTFNFLCAKICAgICAgbmNwID0gNCkKYGBgCgoKYGBge3IsZmlnLmFsaWduPSdjZW50ZXInfQpyZXNfcGNhICU+JSAKICBmdml6X3NjcmVlcGxvdChhZGRsYWJlbHMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICBuY3AgPSA0KQpgYGAKYGBge3J9CnJlc19wY2EkZWlnICU+JSBhc190aWJibGUoKQpgYGAKCjQgQ29tcG9uZW50cyBzZW0gdG8gY2FwdHVyZSBhYm91dCA5MCUgb2YgdGhlIHZhcmlhbmNlLgoKQk9OVVM6IFNvbWUgdmlzdWFsaXphdGlvbjoKCmBgYHtyLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTEwLGZpZy5hbGlnbj0nY2VudGVyJ30KcmVzX3BjYSAlPiUKICBmdml6X3BjYV92YXIoYWxwaGEudmFyID0gImNvczIiLAogICAgICAgICAgICAgICBjb2wudmFyID0gImNvbnRyaWIiLAogICAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwKICAgICAgICAgICAgICAgcmVwZWwgPSBUUlVFLAogICAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfZ3JheSgpKSAKYGBgCgpBbGwgdmFyaWFibGVzIHByZXR0eSBtdWNoIHBvaW50IGludG8gdGhlIHNhbWUgZGlyZWN0aW9uLCBtZWFuaW5nIHRoYXQgd2UgbWFpbmx5IGNhcHR1cmUgYSBzY2FsaW5nIHBoZW5vbWVub24sIHdoZXJlIHZhcmlhYmxlcyB0ZW5kIHRvIG1vdmUgam9pbnRseS4gSG93ZXZlciwgd2UgZG8gc2VlIGluIHRoZSBzZWNvbWQgY29tcG9uZW50LCB2YXJpYWJsZXMgc2VlbSB0byBzcGxpdCBiZXR3ZWVuIGRlZmVuc2l2ZSBhbmQgb2ZmZW5zaXZlIGF0dHJpYnV0ZXMuCgpgYGB7ciwsZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9MTAsZmlnLmFsaWduPSdjZW50ZXInfQpyZXNfcGNhICU+JSAKICBmdml6X3BjYV9iaXBsb3QoYWxwaGEuaW5kID0gImNvczIiLAogICAgICAgICAgICAgICAgICBnZW9tID0gInBvaW50IiwgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgIGhhYmlsbGFnZSA9IGRhdGEgJT4lIHB1bGwoTGVnZW5kYXJ5KSAlPiUgZmFjdG9yKCksIAogICAgICAgICAgICAgICAgICBhZGRFbGxpcHNlcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9ncmF5KCkpIApgYGAKCldlIGdlbmVyYWxseSBzZWUgYWdhaW4gbGVnZW5kYXJ5IHBva2Vtb24gdG8gYmUgbW9yZSBpbiB0aGUgcmlnaHQgcXVhZHJhbnRzIGluZGljYXRpbmcgaGlnaCB2YWx1ZXMgaW4gdGhlaXIgY2hhcmFjdGVyaXN0aWNzLiBIb3dldmVyLCB0aGVyZSBpcyBhIGxhcmdlIGdyZXktem9uZSwgd2hlcmUgdGhlIDJkIHByb2plY3Rpb24gY2Fubm90IHJlYWxseSBkaXN0aW5ndWlzdCBiZXR3ZWVuIGxlZ2VuZGFyeSBhbmQgbm9uLWxlZ2VuZGFyeSBwb2tlbW9ucy4KCmBgYHtyLCxmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0xMCxmaWcuYWxpZ249J2NlbnRlcid9CnJlc19wY2EgJT4lIAogIGZ2aXpfcGNhX2JpcGxvdChhbHBoYS5pbmQgPSAiY29zMiIsCiAgICAgICAgICAgICAgICAgIGdlb20gPSAicG9pbnQiLCAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgaGFiaWxsYWdlID0gZGF0YSAlPiUgcHVsbChUeXBlMSkgJT4lIGZhY3RvcigpLCAKICAgICAgICAgICAgICAgICAgYWRkRWxsaXBzZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfZ3JheSgpKSAKYGBgCgpGb3IgYFR5cGUxYCwgd2UgZ2V0IGEgbWVzcy4uLgoKIyMgVXNlIGEgZGlmZmVyZW50IGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiBtZXRob2QgKGVnLiBVTUFQL05NRikg4oCTZG8gdGhlIGZpbmRpbmdzIGRpZmZlcj8KCldlIGlsbCBydW4gYSBzaW1wbGUgVU1BUAoKYGBge3J9CmxpYnJhcnkodXdvdCkKcmVzX3VtYXAgPC1kYXRhJT4lCiAgc2VsZWN0X2lmKGlzX251bWVyaWMpICU+JQogIHVtYXAobl9uZWlnaGJvcnMgPSAxNSwgCiAgICAgICBtZXRyaWMgPSAiY29zaW5lIiwgCiAgICAgICBtaW5fZGlzdCA9IDAuMDEsIAogICAgICAgc2NhbGUgPSBUUlVFKSAKYGBgCgpgYGB7cn0KcmVzX3VtYXAgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgYmluZF9jb2xzKGRhdGEgJT4lIHNlbGVjdChMZWdlbmRhcnkpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBWMSwgeSA9IFYyLCBjb2wgPSBMZWdlbmRhcnkpKSArIAogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgYWxwaGEgPSAwLjUpIApgYGAKCldlbGwsIFVNQVAgc2VlbXMgdG8gZG8gYSBiZXR0ZXIgam9iIGluIHNlcHBlcmF0aW9uIGhpZ2ggYW5kIGxvdyBwZXJmb3JtaW5nIHBva2Vtb25zIGluIHNwYWN3LiBIb3dldmVyLCB3ZSBhbHNvIHNlZSB0aGF0IG9ubHkgc29tZXdoYXQgaGVscHMgdXMgdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiBsZWdlbmRhcnkgYW5kIG5vbi1sZWdlbmRhcnkgb25lcy4KCmBgYHtyfQpyZXNfdW1hcCAlPiUKICBhc190aWJibGUoKSAlPiUKICBiaW5kX2NvbHMoZGF0YSAlPiUgc2VsZWN0KFR5cGUxKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gVjEsIHkgPSBWMiwgY29sID0gVHlwZTEpKSArIAogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgYWxwaGEgPSAwLjUpIApgYGAKU2FtZSBnb2VzIGZvciB0eXBlcy4uLgoKIyMgNC4gUGVyZm9ybSBhIGNsdXN0ZXIgYW5hbHlzaXMgKEtNZWFucykgb24gYWxsIG51bWVyaWNhbCB2YXJpYWJsZXMgKHNjYWxlZCAmIGJlZm9yZSBQQ0EpLiBQaWNrIGEgcmVhbGlzdGljIG51bWJlciBvZiBjbHVzdGVycyAodXAgdG8geW91IHdoZXJlIHRoZSBsYXJnZSBjbHVzdGVycyByZW1haW4gbW9zdGx5IHN0YWJsZSkuCgpgYGB7cixmaWcuYWxpZ249J2NlbnRlcid9CiMgV2UgdXNlIHRoZSB2aXpfbmJjbHVzdCgpIGZ1bmN0aW9uIG9mIHRoZSBmYWN0b3JleHRyYSBwYWNrYWdlCmRhdGEgJT4lCiAgc2VsZWN0X2lmKGlzX251bWVyaWMpICU+JSAKICBzY2FsZSgpICU+JQogIGZ2aXpfbmJjbHVzdChrbWVhbnMsIG1ldGhvZCA9ICJ3c3MiKSAgCmBgYApPayx3ZSBoZXJlIHNldHRsZSBmb3IgMiAoZXhlY3V0aXZlIGRlY2lzaW9uLCBzaW5jZSB3ZSB3YW50IHRvIGlkZW50aWZ5IDIgZGlzdGluY3QgY2xhc3NlcykuIAoKYGBge3J9CnJlc19rbSA8LSBkYXRhICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoJ05hbWUnKSAlPiUKICBzZWxlY3RfaWYoaXNfbnVtZXJpYykgJT4lCiAgc2NhbGUoKSAlPiUgCiAga21lYW5zKGNlbnRlcnMgPSAyLCBuc3RhcnQgPSAyMCkgIApgYGAKCiMjIDUuVmlzdWFsaXplIHRoZSBmaXJzdCAyIHByaW5jaXBhbCBjb21wb25lbnRzIGFuZCBjb2xvciB0aGUgZGF0YXBvaW50cyBieSBjbHVzdGVyLgoKYGBge3IsLGZpZy53aWR0aD0xNSxmaWcuaGVpZ2h0PTEwLGZpZy5hbGlnbj0nY2VudGVyJ30KcmVzX2ttICU+JSAKICBmdml6X2NsdXN0ZXIoZGF0YSA9IGRhdGEgJT4lIHNlbGVjdF9pZihpc19udW1lcmljKSkgIApgYGAKCiMjIDYuSW5zcGVjdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB2YXJpYWJsZSDigJxUeXBlMeKAnSBhY3Jvc3MgY2x1c3RlcnMuIERvZXMgdGhlIGFsZ29yaXRobSBzZXBhcmF0ZSB0aGUgZGlmZmVyZW50IHR5cGVzIG9mIHBva2Vtb24/CgpgYGB7cn0KdGFibGUoZGF0YSRUeXBlMSwgcmVzX2ttJGNsdXN0ZXIpCmBgYAoKV2VsbCwgbm90IHJlYWxseS4gSG93ZXZlciwgaW4gY2FzZSBJIHdvdWxkIGhhdmUgc2VsZWN0ZWQgbW9yZSwgZm9yIGluc3RhbmNlIDQsIGNsdXN0ZXJzLCBJIG1pZ2h0IGhhdmUgaGFkIGEgZGlmZmVyZW50IHBpY3R1cmUuCgpgYGB7cn0KZGF0YSAlPiUKICBiaW5kX2NvbHMoY2x1c3RlciA9IHJlc19rbSRjbHVzdGVyKSAlPiUKICBzZWxlY3RfaWYoaXNfbnVtZXJpYykgJT4lCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgbXV0YXRlKG4gPSBuKCkpICU+JQogIHN1bW1hcmlzZV9hbGwoZnVucyhtZWFuKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKC1jbHVzdGVyKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY2x1c3RlciwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkKYGBgCgpBcyB3ZSBhbHJlYWR5IGd1ZXNzZWQsIHRoZSAyIGNsdXN0ZXJzIGFyZSBtYWlubHkgZm9ybWVkIGJ5IG92ZXJhbGwgaGlnaCBvciBsb3cgYXR0cmlidXRlcy4KCiMjIDcuUGVyZm9ybSBhIGNsdXN0ZXIgYW5hbHlzaXMgb24gYWxsIG51bWVyaWNhbCB2YXJpYWJsZXMgc2NhbGVkIGFuZCBBRlRFUiBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gYW5kIHZpc3VhbGl6ZSB0aGUgZmlyc3QgMiBwcmluY2lwYWwgY29tcG9uZW50cy4KClNpbmNlIHdlIGRpZG50IHNwZWNpZnkgd2hpY2ggdHlwZSBvZiBjbHVzdGVyaW5nLCB3ZSBjYW5uIGFsc28gZG8gaGlyYXJjaGljYWwgY2x1c3RlcmluZyBub3cgYW5kIHVzZSB0aGUgSENQQ0EgZnVuY3Rpb24gZm9yIGNvbnZlbmllbmNlLgoKYGBge3J9CnJlc19oY3BjIDwtIHJlc19wY2EgJT4lIAogIEhDUEMobmIuY2x1c3QgPSAtMSwgIyAgc2VsZiBkZXRlcm1pbmVkOiBoaWdoZXIgcmVsYXRpdmUgbG9zcyBvZiBpbmVydGlhCiAgICAgICBncmFwaCA9IEZBTFNFKSAKYGBgCgpgYGB7ciwsZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MTAsZmlnLmFsaWduPSdjZW50ZXInfQpyZXNfaGNwYyAlPiUKICBwbG90KGNob2ljZSA9ICIzRC5tYXAiKQpgYGAKCkludGVyZXN0aW5nbHksIGhlcmUgd2Ugd291bGQgaGF2ZSAzIGNsdXN0ZXJzLCB3aXRoIG9uZSBpbiB0aGUgbWlkZGxlLgoKIyMgOC5BZ2FpbiwgaW5zcGVjdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB2YXJpYWJsZSDigJxUeXBlIDHigJ0gYWNyb3NzIGNsdXN0ZXJzLCBkb2VzIGl0IGRpZmZlciBmcm9tIHRoZSBkaXN0cmlidXRpb24gYmVmb3JlIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbj8KCmBgYHtyfQp0YWJsZShkYXRhJFR5cGUxLCByZXNfaGNwYyRkYXRhLmNsdXN0JGNsdXN0KQpgYGAKCldlbGwsIG5vdCByZWFsbCBpbiBtb3N0IGNhc2VzLi4uCg==