RPubs link: https://rpubs.com/enewington/722829

Presentation link: https://www.loom.com/share/5958c725f69940ffaf8511193808776d

Required packages

# Load Packages 
library(readr) 
library(dplyr)
library(tidyverse)
library(outliers)
library(MVN)
library(magrittr) #pipe operator
library(forecast) # For finding lambda for a Box-Cox transformation 
library(Hmisc) #impute missing

Data

The datasets have been obtained from:

https://data.world/data-society/pokemon-with-stats

https://www.kaggle.com/mylesoneill/pokemon-sun-and-moon-gen-7-stats?select=type-chart.csv NOTE dataset2 source seems to have differed from when the data was originally downloaded

The two data sets includes statistics on 898 Pokemon. The variable descriptions are as follows:

Pokedex: The unique ID for each pokemon

Name: The name of each pokemon

Type 1: Determines weakness/resistance to attacks

Type 2: Some pokemon are dual type and have a second type

Total: Sum of all stats that come after this, a general guide to how strong a pokemon is

HP: Hit points, or health, defines how much damage a pokemon can withstand before fainting

Attack: The base modifier for normal attacks (eg. Scratch, Punch)

Defense: The base damage resistance against normal attacks

SP Atk: Special attack, the base modifier for special attacks (e.g. fire blast, bubble beam)

SP Def: Special defense, the base damage resistance against special attacks

Speed: Determines which pokemon attacks first each round

Generation: The generation of games where the pokemon was first introduced

Legendary: Some pokemon are much rarer than others, and are dubbed “legendary”

Species: as per name

Forme: as per name

Ability 1: an effect on a Pokémon that is not an attack. Some will be active all of the time, while some you will need to choose to use.

Ability 2: Some Pokemon have a second ability

Total: total of HP,attack, defense, spattack, spdefense and speed

Weight: weight of the pokemon

Height: height of the pokemon

dex 1: unknown: dex is usually short for ‘pokedex’. the contents of this variable are not understood

dex 2: as above

class: each move is classified as one of the 18 Pokémon types. The effectiveness of a move is dependent on how susceptible the target Pokémon’s type is to the move’s type.

percent-male: percentage of male pokemon of this species/name

percent-female: percentage of female pokemon of this species/name

egg-group: categories which determine which Pokémon are able to interbreed. A Pokémon may belong to either one or two Egg Groups.

egg-group2: as above

Date.first.spawned: date the pokemon was first discovered

Read data

The csv files have been imported using the base R read.csv package, specifying that not all strings should automatically be converted to factors. There are more character variables than factor variables, so the factors will be automatically converted later. There are many empty cells, so na.strings will ensure empty cells are filled with NA, to make tidying the data easier. To inspect the datasets, head() has been use to view the first 6 rows of each dataset and dim() has been used for a quick glance at the dimensions of the datasets. Pokemon1 has 800 rows (observations) and 15 columns (variables) and Pokemon2 has 1060 rows and 26 columns.

#read data
pokemon1 <- read.csv('pokemon data1.csv', stringsAsFactors = FALSE, na.strings="")
pokemon2 <- read.csv('pokemon data2.csv', stringsAsFactors = FALSE, na.strings="")
#view the first 6 rows of data
head(pokemon1)
head(pokemon2)
dim(pokemon1)
[1] 800  15
dim(pokemon2)
[1] 1061   26

Pre-merge data tidying

The datasets will undergo some initial tidying before they are merged, to ensure both datasets contain the same unique. Dataset one contains data on the first 721 pokemon, so dataset 2 will drop any pokemon that have a pokedex(index) number higher than 721.

Tidy dataset 1

#remove the first variable as this is identical to the pokdex number, both are not required
pokemon1 <- pokemon1[ , -(1)]
head(pokemon1)
#CHECK FOR DUPLICATES
any(duplicated(pokemon1$pokedex))
[1] TRUE
#to start with, remove any rows containing 'mega'as these are evolved forms of pokemon and we will only analyse original pokemon
pokemon1[- grep("Mega", pokemon1$Name),]
#remove any other duplicates in pokedex
pokemon1 %<>% distinct(pokedex, .keep_all = TRUE)

#CHECK FOR DUPLICATES - now the list is unique
any(duplicated(pokemon1$pokedex))
[1] FALSE

Tidy dataset 2

#drop pokemon in the pokedex greater than 722 to ensure the datasets contain the same pokemon and remove the unnecessary ID columbn
pokemon2 %<>% 
  filter(pokedex<722) %>% 
  select(-id)
head(pokemon2)
dim(pokemon2)
[1] 936  25
#remove duplicates
pokemon2 %<>% distinct(pokedex, .keep_all = TRUE)

#CHECK FOR DUPLICATES
any(duplicated(pokemon2$pokedex))
[1] FALSE
dim(pokemon2)
[1] 721  25

Merge the datasets

The datasets have been merged using a full join with pokedex as the primary key. The pokedex acts like an index, with each unique pokemon having a reference on the pokedex. The full join has been used to return all rows and all columns from both pokemon1 and pokemon2 datasets. If there there happens to be no matching value, there will be an NA returned for the one missing.

#JOIN DATASETS
pokemon_df <- pokemon1 %>% 
  full_join(pokemon2, by = 'pokedex')
dim(pokemon_df)
[1] 721  38

Understand

The str() functions shows all the types of data. As we used stringasfactors=FALSE when reading the data, there are no factors in this list, however Type should be an ordered factor, as certain types are stronger than others, and date will also need to be converted. The summary() function shows the range of each variable, where it is numeric, the min, max, medial and quartiles 1 and 3. Where it’s a character variable, the class and mode are shown.

str(pokemon_df)
'data.frame':   721 obs. of  38 variables:
 $ pokedex           : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Name              : chr  "Bulbasaur" "Ivysaur" "Venusaur" "Charmander" ...
 $ Type.1            : chr  "Grass" "Grass" "Grass" "Fire" ...
 $ Type.2            : chr  "Poison" "Poison" "Poison" NA ...
 $ Total             : int  318 405 525 309 405 534 314 405 530 195 ...
 $ HP                : int  45 60 80 39 58 78 44 59 79 45 ...
 $ Attack            : int  49 62 82 52 64 84 48 63 83 30 ...
 $ Defense           : int  49 63 83 43 58 78 65 80 100 35 ...
 $ Sp..Atk           : int  65 80 100 60 80 109 50 65 85 20 ...
 $ Sp..Def           : int  65 80 100 50 65 85 64 80 105 20 ...
 $ Speed             : int  45 60 80 65 80 100 43 58 78 45 ...
 $ Generation        : int  1 1 1 1 1 1 1 1 1 1 ...
 $ Legendary         : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ Date.first.spawned: chr  "12/12/1995" "10/11/2018" "16/11/1987" "30/05/1996" ...
 $ species           : chr  "Bulbasaur" "Ivysaur" "Venusaur" "Charmander" ...
 $ forme             : chr  "Bulbasaur" "Ivysaur" "Venusaur" "Charmander" ...
 $ type1             : chr  "Grass" "Grass" "Grass" "Fire" ...
 $ type2             : chr  "Poison" "Poison" "Poison" NA ...
 $ ability1          : chr  "Overgrow" "Overgrow" "Overgrow" "Blaze" ...
 $ ability2          : chr  NA NA NA NA ...
 $ abilityH          : chr  "Chlorophyll" "Chlorophyll" "Chlorophyll" "Solar Power" ...
 $ hp                : int  45 60 80 39 58 78 44 59 79 45 ...
 $ attack            : int  49 62 82 52 64 84 48 63 83 30 ...
 $ defense           : int  49 63 83 43 58 78 65 80 100 35 ...
 $ spattack          : int  65 80 100 60 80 109 50 65 85 20 ...
 $ spdefense         : int  65 80 100 50 65 85 64 80 105 20 ...
 $ speed             : int  45 60 80 65 80 100 43 58 78 45 ...
 $ total             : int  318 405 525 309 405 534 314 405 530 195 ...
 $ weight            : chr  "15.2 lbs." "28.7 lbs." "220.5 lbs." "18.7 lbs." ...
 $ height            : chr  "2'04\"" "3'03\"" "6'07\"" "2'00\"" ...
 $ dex1              : chr  NA NA NA NA ...
 $ dex2              : chr  NA NA NA NA ...
 $ class             : chr  "Seed Pokémon" "Seed Pokémon" "Seed Pokémon" "Lizard Pokémon" ...
 $ percent.male      : num  0.875 0.875 0.875 0.875 0.875 0.875 0.875 0.875 0.875 0.5 ...
 $ percent.female    : num  0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.5 ...
 $ pre.evolution     : chr  NA "Bulbasaur" "Ivysaur" NA ...
 $ egg.group1        : chr  "Monster" "Monster" "Monster" "Monster" ...
 $ egg.group2        : chr  "Grass" "Grass" "Grass" "Dragon" ...
summary(pokemon_df)
    pokedex        Name              Type.1             Type.2              Total             HP        
 Min.   :  1   Length:721         Length:721         Length:721         Min.   :180.0   Min.   :  1.00  
 1st Qu.:181   Class :character   Class :character   Class :character   1st Qu.:320.0   1st Qu.: 50.00  
 Median :361   Mode  :character   Mode  :character   Mode  :character   Median :424.0   Median : 65.00  
 Mean   :361                                                            Mean   :417.9   Mean   : 68.38  
 3rd Qu.:541                                                            3rd Qu.:499.0   3rd Qu.: 80.00  
 Max.   :721                                                            Max.   :720.0   Max.   :255.00  
                                                                                                        
     Attack          Defense         Sp..Atk          Sp..Def           Speed          Generation   
 Min.   :  5.00   Min.   :  5.0   Min.   : 10.00   Min.   : 20.00   Min.   :  5.00   Min.   :1.000  
 1st Qu.: 54.00   1st Qu.: 50.0   1st Qu.: 45.00   1st Qu.: 50.00   1st Qu.: 45.00   1st Qu.:2.000  
 Median : 75.00   Median : 65.0   Median : 65.00   Median : 65.00   Median : 65.00   Median :3.000  
 Mean   : 75.12   Mean   : 70.7   Mean   : 68.85   Mean   : 69.18   Mean   : 65.71   Mean   :3.323  
 3rd Qu.: 95.00   3rd Qu.: 85.0   3rd Qu.: 90.00   3rd Qu.: 85.00   3rd Qu.: 85.00   3rd Qu.:5.000  
 Max.   :165.00   Max.   :230.0   Max.   :154.00   Max.   :230.00   Max.   :160.00   Max.   :6.000  
                                                                                                    
 Legendary       Date.first.spawned   species             forme              type1              type2          
 Mode :logical   Length:721         Length:721         Length:721         Length:721         Length:721        
 FALSE:675       Class :character   Class :character   Class :character   Class :character   Class :character  
 TRUE :46        Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                                                               
                                                                                                               
                                                                                                               
                                                                                                               
   ability1           ability2           abilityH               hp             attack         defense      
 Length:721         Length:721         Length:721         Min.   :  1.00   Min.   :  5.0   Min.   :  5.00  
 Class :character   Class :character   Class :character   1st Qu.: 50.00   1st Qu.: 53.0   1st Qu.: 50.00  
 Mode  :character   Mode  :character   Mode  :character   Median : 65.00   Median : 75.0   Median : 66.00  
                                                          Mean   : 68.53   Mean   : 75.1   Mean   : 70.96  
                                                          3rd Qu.: 80.00   3rd Qu.: 95.0   3rd Qu.: 85.00  
                                                          Max.   :255.00   Max.   :165.0   Max.   :230.00  
                                                                                                           
    spattack        spdefense         speed            total          weight             height         
 Min.   : 10.00   Min.   : 20.0   Min.   :  5.00   Min.   :180.0   Length:721         Length:721        
 1st Qu.: 45.00   1st Qu.: 50.0   1st Qu.: 45.00   1st Qu.:320.0   Class :character   Class :character  
 Median : 65.00   Median : 65.0   Median : 65.00   Median :425.0   Mode  :character   Mode  :character  
 Mean   : 68.81   Mean   : 69.4   Mean   : 65.78   Mean   :418.6                                        
 3rd Qu.: 90.00   3rd Qu.: 85.0   3rd Qu.: 85.00   3rd Qu.:500.0                                        
 Max.   :154.00   Max.   :230.0   Max.   :160.00   Max.   :720.0                                        
                                                                                                        
     dex1               dex2              class            percent.male   percent.female  pre.evolution     
 Length:721         Length:721         Length:721         Min.   :0.000   Min.   :0.000   Length:721        
 Class :character   Class :character   Class :character   1st Qu.:0.500   1st Qu.:0.500   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Median :0.500   Median :0.500   Mode  :character  
                                                          Mean   :0.558   Mean   :0.442                     
                                                          3rd Qu.:0.500   3rd Qu.:0.500                     
                                                          Max.   :1.000   Max.   :1.000                     
                                                          NA's   :72      NA's   :72                        
  egg.group1         egg.group2       
 Length:721         Length:721        
 Class :character   Class :character  
 Mode  :character   Mode  :character  
                                      
                                      
                                      
                                      

apply data conversions

Type 1 has been converted to a factor and then the ordered levels have been applied. Date.first.spawned has been converted from character to date.

#order variables that have a hierarchy
pokemon_df$type1 <-  as.factor(pokemon_df$type1)
str(pokemon_df$type1)
 Ord.factor w/ 18 levels "Dragon"<"Fairy"<..: 15 15 15 8 8 8 3 3 3 17 ...
#order variables that have a hierarchy
pokemon_df$type1 <-  factor(pokemon_df$type1,
                    levels=c('Dragon',
                             'Fairy', 
                             'Water',
                             'Steel',
                             'Fighting',
                             'Dark',
                             'Flying',
                             'Fire',
                             'Ghost',
                             'Ground',
                             'Normal',
                             'Psychic',
                             'Electric',
                             'Poison',
                             'Grass',
                             'Rock',
                             'Bug',
                             'Ice'),
                    ordered=TRUE)

#convert date from character to date
pokemon_df$Date.first.spawned <- as.Date(pokemon_df$Date.first.spawned)
str(pokemon_df)
'data.frame':   721 obs. of  38 variables:
 $ pokedex           : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Name              : chr  "Bulbasaur" "Ivysaur" "Venusaur" "Charmander" ...
 $ Type.1            : chr  "Grass" "Grass" "Grass" "Fire" ...
 $ Type.2            : chr  "Poison" "Poison" "Poison" NA ...
 $ Total             : int  318 405 525 309 405 534 314 405 530 195 ...
 $ HP                : int  45 60 80 39 58 78 44 59 79 45 ...
 $ Attack            : int  49 62 82 52 64 84 48 63 83 30 ...
 $ Defense           : int  49 63 83 43 58 78 65 80 100 35 ...
 $ Sp..Atk           : int  65 80 100 60 80 109 50 65 85 20 ...
 $ Sp..Def           : int  65 80 100 50 65 85 64 80 105 20 ...
 $ Speed             : int  45 60 80 65 80 100 43 58 78 45 ...
 $ Generation        : int  1 1 1 1 1 1 1 1 1 1 ...
 $ Legendary         : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ Date.first.spawned: Date, format: "0012-12-19" "0010-11-20" "0016-11-19" "0030-05-19" ...
 $ species           : chr  "Bulbasaur" "Ivysaur" "Venusaur" "Charmander" ...
 $ forme             : chr  "Bulbasaur" "Ivysaur" "Venusaur" "Charmander" ...
 $ type1             : Ord.factor w/ 18 levels "Dragon"<"Fairy"<..: 15 15 15 8 8 8 3 3 3 17 ...
 $ type2             : chr  "Poison" "Poison" "Poison" NA ...
 $ ability1          : chr  "Overgrow" "Overgrow" "Overgrow" "Blaze" ...
 $ ability2          : chr  NA NA NA NA ...
 $ abilityH          : chr  "Chlorophyll" "Chlorophyll" "Chlorophyll" "Solar Power" ...
 $ hp                : int  45 60 80 39 58 78 44 59 79 45 ...
 $ attack            : int  49 62 82 52 64 84 48 63 83 30 ...
 $ defense           : int  49 63 83 43 58 78 65 80 100 35 ...
 $ spattack          : int  65 80 100 60 80 109 50 65 85 20 ...
 $ spdefense         : int  65 80 100 50 65 85 64 80 105 20 ...
 $ speed             : int  45 60 80 65 80 100 43 58 78 45 ...
 $ total             : int  318 405 525 309 405 534 314 405 530 195 ...
 $ weight            : chr  "15.2 lbs." "28.7 lbs." "220.5 lbs." "18.7 lbs." ...
 $ height            : chr  "2'04\"" "3'03\"" "6'07\"" "2'00\"" ...
 $ dex1              : chr  NA NA NA NA ...
 $ dex2              : chr  NA NA NA NA ...
 $ class             : chr  "Seed Pokémon" "Seed Pokémon" "Seed Pokémon" "Lizard Pokémon" ...
 $ percent.male      : num  0.875 0.875 0.875 0.875 0.875 0.875 0.875 0.875 0.875 0.5 ...
 $ percent.female    : num  0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.5 ...
 $ pre.evolution     : chr  NA "Bulbasaur" "Ivysaur" NA ...
 $ egg.group1        : chr  "Monster" "Monster" "Monster" "Monster" ...
 $ egg.group2        : chr  "Grass" "Grass" "Grass" "Dragon" ...

Tidy & Manipulate Data I

To check if this data is tidy, comparisons between the similar variables have been made. Firstly identical() is used to see if the two colums are identical or not, if not then which() is used to see which observations are different. All of the similar variables have been 2 and 24 variables, so a decision to keep the variables from pokemon2 has been made. Some variables have been renames to avoid confusion (e.g. the variable ‘class’ could be confused with class()) Forme has been changed to form Any instances of ‘Pokémon’ have been dropped from the column class/pokeclass

#compare similar variables
identical(pokemon_df[['Name']],pokemon_df[['species']])
[1] FALSE
pokemon_df[which(pokemon_df$Name != pokemon_df$species), ]

identical(pokemon_df[['Type.1']],pokemon_df[['type1']])
[1] FALSE
pokemon_df[which(pokemon_df$Type.1 != pokemon_df$type1), ]

identical(pokemon_df[['Type.1']],pokemon_df[['type2']])
[1] FALSE
pokemon_df[which(pokemon_df$Type.2 != pokemon_df$type2), ]

identical(pokemon_df[['HP']],pokemon_df[['hp']])
[1] FALSE
pokemon_df[which(pokemon_df$HP != pokemon_df$hp), ]

identical(pokemon_df[['Attack']],pokemon_df[['attack']])
[1] FALSE
pokemon_df[which(pokemon_df$Attack != pokemon_df$attack), ]

identical(pokemon_df[['Defense']],pokemon_df[['defense']])
[1] FALSE
pokemon_df[which(pokemon_df$Defense != pokemon_df$defense), ]

identical(pokemon_df[['Sp..Atk']],pokemon_df[['spattack']])
[1] FALSE
pokemon_df[which(pokemon_df$Sp..Atk != pokemon_df$spattack), ]

identical(pokemon_df[['Sp..Def']],pokemon_df[['spdefense']])
[1] FALSE
pokemon_df[which(pokemon_df$Sp..Def != pokemon_df$spdefense), ]

identical(pokemon_df[['Speed']],pokemon_df[['speed']])
[1] FALSE
pokemon_df[which(pokemon_df$Speed != pokemon_df$speed), ]

identical(pokemon_df[['Total']],pokemon_df[['total']])
[1] FALSE
pokemon_df[which(pokemon_df$Total != pokemon_df$total), ]

#drop unnecessary columns - keep the values from pokemon data2
pokemon_df2 <- select(pokemon_df, -Name, -HP, -Attack, -Defense, -Sp..Atk, -Sp..Def, -Speed, -Total, -dex1, -dex2, -Type.1, -Type.2)

#rename class to avoid confusion with class()
pokemon_df2 %<>% 
  rename(pokeclass = class)

#rename 'forme' to form
pokemon_df2 %<>% 
  rename(form = forme)

#remove special characters from class column
pokemon_df2$pokeclass %<>% str_replace("Pokémon","")
head(pokemon_df2)
dim(pokemon_df2)
[1] 721  26
str(pokemon_df2)
'data.frame':   721 obs. of  26 variables:
 $ pokedex           : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Generation        : int  1 1 1 1 1 1 1 1 1 1 ...
 $ Legendary         : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ Date.first.spawned: Date, format: "0012-12-19" "0010-11-20" "0016-11-19" "0030-05-19" ...
 $ species           : chr  "Bulbasaur" "Ivysaur" "Venusaur" "Charmander" ...
 $ form              : chr  "Bulbasaur" "Ivysaur" "Venusaur" "Charmander" ...
 $ type1             : Ord.factor w/ 18 levels "Dragon"<"Fairy"<..: 15 15 15 8 8 8 3 3 3 17 ...
 $ type2             : chr  "Poison" "Poison" "Poison" NA ...
 $ ability1          : chr  "Overgrow" "Overgrow" "Overgrow" "Blaze" ...
 $ ability2          : chr  NA NA NA NA ...
 $ abilityH          : chr  "Chlorophyll" "Chlorophyll" "Chlorophyll" "Solar Power" ...
 $ hp                : int  45 60 80 39 58 78 44 59 79 45 ...
 $ attack            : int  49 62 82 52 64 84 48 63 83 30 ...
 $ defense           : int  49 63 83 43 58 78 65 80 100 35 ...
 $ spattack          : int  65 80 100 60 80 109 50 65 85 20 ...
 $ spdefense         : int  65 80 100 50 65 85 64 80 105 20 ...
 $ speed             : int  45 60 80 65 80 100 43 58 78 45 ...
 $ total             : int  318 405 525 309 405 534 314 405 530 195 ...
 $ weight            : chr  "15.2 lbs." "28.7 lbs." "220.5 lbs." "18.7 lbs." ...
 $ height            : chr  "2'04\"" "3'03\"" "6'07\"" "2'00\"" ...
 $ pokeclass         : chr  "Seed " "Seed " "Seed " "Lizard " ...
 $ percent.male      : num  0.875 0.875 0.875 0.875 0.875 0.875 0.875 0.875 0.875 0.5 ...
 $ percent.female    : num  0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.125 0.5 ...
 $ pre.evolution     : chr  NA "Bulbasaur" "Ivysaur" NA ...
 $ egg.group1        : chr  "Monster" "Monster" "Monster" "Monster" ...
 $ egg.group2        : chr  "Grass" "Grass" "Grass" "Dragon" ...

Tidy & Manipulate Data II

A new column has been created using mutate() to add together attack and spattack for each pokemon, in a new column called ‘totalattack’

#create total attack points column
mutate(pokemon_df2, totalattack = attack+spattack) 

Scan I

colSums() has been used to see how many missing values are in each column. At this stage, 7 columns have missing values. The percentage of female and male variables have been imputed with the mean, using impute() The variables type2, ability, pre.evolution and egg.group2 have blank values in some obsverations, but this is not missing data, as not all pokemon have these attributes. Where there in an NA in these observations, we will replace the NA with a string to make it clear that the attribute is not applible rather than missing. AbilityH will be replaced with the mode, or most commonly appearing abilityH

#Look for missing values
colSums(is.na(pokemon_df2))
           pokedex         Generation          Legendary Date.first.spawned            species 
                 0                  0                  0                  0                  0 
              form              type1              type2           ability1           ability2 
                 0                  0                372                  0                310 
          abilityH                 hp             attack            defense           spattack 
                83                  0                  0                  0                  0 
         spdefense              speed              total             weight             height 
                 0                  0                  0                  0                  0 
         pokeclass       percent.male     percent.female      pre.evolution         egg.group1 
                 0                 72                 72                365                  0 
        egg.group2 
               530 
#impute missing values with mean
pokemon_df2$percent.male %<>% impute(pokemon_df2$percent.male, fun = mean)
pokemon_df2$percent.female %<>% impute(pokemon_df2$percent.female, fun = mean)

#type 2, ability 2, pre.evolution and and egg group 2 all have over half the observations missing however this is not missing data, these pokemon do not have these attributes and these columns should not be dropped. Cells will be filled with a new string
pokemon_df2$type2 %<>% replace_na("no type 2")
pokemon_df2$ability2 %<>% replace_na("no ability 2")
pokemon_df2$pre.evolution %<>% replace_na("no pre-evolution")
pokemon_df2$egg.group2 %<>% replace_na("no egg group 2")

#ability H will be replaced with the mode
pokemon_df2$abilityH %<>% impute(pokemon_df2$abilityH, fun= mode)

#Look again for missing values
colSums(is.na(pokemon_df2))
           pokedex         Generation          Legendary Date.first.spawned            species 
                 0                  0                  0                  0                  0 
              form              type1              type2           ability1           ability2 
                 0                  0                  0                  0                  0 
          abilityH                 hp             attack            defense           spattack 
                 0                  0                  0                  0                  0 
         spdefense              speed              total             weight             height 
                 0                  0                  0                  0                  0 
         pokeclass       percent.male     percent.female      pre.evolution         egg.group1 
                 0                  0                  0                  0                  0 
        egg.group2 
                 0 

Scan II

As there are many numeric variables, a multivariate analysis has been chosen. Firstly, a subset of only numeric variables is made. As all missing values have been taken care of, the addition step of removing missing values is not needed. MVN is used to find and exclude the mutlivariate outliers and return the observation numbers of the outliers. The data is then subset again to exclude the observations that contain the outliers.

# Subset the dataset to relevant numeric variables
pokemon_sub <- pokemon_df2 %>% select(hp, attack,defense, spattack, spdefense, speed, total) 
dim(pokemon_sub)
[1] 721   7
# Find and exclude the multivariate outliers 
pokeresults <- pokemon_sub %>% 
  MVN::mvn(multivariateOutlierMethod = "quan", 
           showOutliers = TRUE)
The covariance matrix has become singular during
the iterations of the MCD algorithm.
There are 721 observations (in the entire dataset of 721 obs.) lying on the hyperplane with equation
a_1*(x_i1 - m_1) + ... + a_p*(x_ip - m_p) = 0 with (m_1, ..., m_p) the mean of these observations
and coefficients a_i from the vector a <- c(-0.3779645, -0.3779645, -0.3779645, -0.3779645,
-0.3779645, -0.3779645, 0.3779645)

pokeresults$multivariateOutliers
#returns the observation numbers of the outliers and then converts from character to numeric
pokemon_outliers <- pokemon_sub[c(as.numeric(pokeresults$multivariateOutliers[["Observation"]])), ]

# # subset the dataset by including rows contain in the specified observation numbers 
pokemon_clean <- pokemon_sub[-c(as.numeric(pokeresults$multivariateOutliers[["Observation"]])), ]
dim(pokemon_clean)
[1] 713   7
dim(pokemon_outliers)
[1] 8 7
dim(pokemon_sub)
[1] 721   7

Transform

The histogram of hp is very right skewed. A box-cox transformation has been applied, where the lamba is automatically found and applied. After the transformation, the shape of the histogram is slightly more normalise, however there is nowa slight left skew.

#create a histogram
hist(pokemon_df2$hp)

#Apply Box-Cox transformation 
boxcox_hp <- BoxCox(pokemon_df2$hp, lambda = "auto")
attr(boxcox_hp, which = "lambda")
[1] 0.1990125
hist(boxcox_hp)

##References

Biostars. (2020, 02 01). Question: Find mismatch in two columns in a data frame in R. Retrieved from Biostars; bioinformatics explained: https://www.biostars.org/p/180451/

DataNovia. (2021, 01 02). Identify and Remove Duplicate Data in R . Retrieved from DataNovia: https://www.datanovia.com/en/lessons/identify-and-remove-duplicate-data-in-r/

Fontes, R. (2021, 02 12). Pokémon: Every Elemental Type, Officially Ranked. Retrieved from Thegamer: https://www.thegamer.com/pokemon-elemental-types-ranked-officially/

intelliPaat. (2021, 02 11). Change the Blank Cells to “NA”. Retrieved from intellipaat: https://intellipaat.com/community/27103/change-the-blank-cells-to-na

Wickham, H. (2021, 02 11). Replace NAs with specified values. Retrieved from tidyr: https://tidyr.tidyverse.org/reference/replace_na.html

LS0tDQp0aXRsZTogIkRhdGEgV3JhbmdsaW5nIEFzc2Vzc21lbnQgVGFzayAzOiBEYXRhc2V0IGNoYWxsZW5nZSINCmF1dGhvcjogIkVyaW4gTmV3aW5ndG9uIHwgczM4ODQ2MTQiDQpzdWJ0aXRsZTogDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCi0tLQ0KDQpSUHVicyBsaW5rOiBodHRwczovL3JwdWJzLmNvbS9lbmV3aW5ndG9uLzcyMjgyOQ0KDQpQcmVzZW50YXRpb24gbGluazogaHR0cHM6Ly93d3cubG9vbS5jb20vc2hhcmUvNTk1OGM3MjVmNjk5NDBmZmFmODUxMTE5MzgwODc3NmQNCg0KIyMgUmVxdWlyZWQgcGFja2FnZXMgDQoNCmBgYHtyfQ0KIyBMb2FkIFBhY2thZ2VzIA0KbGlicmFyeShyZWFkcikgDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KG91dGxpZXJzKQ0KbGlicmFyeShNVk4pDQpsaWJyYXJ5KG1hZ3JpdHRyKSAjcGlwZSBvcGVyYXRvcg0KbGlicmFyeShmb3JlY2FzdCkgIyBGb3IgZmluZGluZyBsYW1iZGEgZm9yIGEgQm94LUNveCB0cmFuc2Zvcm1hdGlvbiANCmxpYnJhcnkoSG1pc2MpICNpbXB1dGUgbWlzc2luZw0KYGBgDQoNCiMjIERhdGEgDQpUaGUgZGF0YXNldHMgaGF2ZSBiZWVuIG9idGFpbmVkIGZyb206DQoNCmh0dHBzOi8vZGF0YS53b3JsZC9kYXRhLXNvY2lldHkvcG9rZW1vbi13aXRoLXN0YXRzDQoNCmh0dHBzOi8vd3d3LmthZ2dsZS5jb20vbXlsZXNvbmVpbGwvcG9rZW1vbi1zdW4tYW5kLW1vb24tZ2VuLTctc3RhdHM/c2VsZWN0PXR5cGUtY2hhcnQuY3N2DQoqTk9URSBkYXRhc2V0MiBzb3VyY2Ugc2VlbXMgdG8gaGF2ZSBkaWZmZXJlZCBmcm9tIHdoZW4gdGhlIGRhdGEgd2FzIG9yaWdpbmFsbHkgZG93bmxvYWRlZCoNCg0KVGhlIHR3byBkYXRhIHNldHMgaW5jbHVkZXMgc3RhdGlzdGljcyBvbiA4OTggUG9rZW1vbi4gVGhlIHZhcmlhYmxlIGRlc2NyaXB0aW9ucyBhcmUgYXMgZm9sbG93czoNCg0KKipQb2tlZGV4OioqIFRoZSB1bmlxdWUgSUQgZm9yIGVhY2ggcG9rZW1vbg0KDQoqKk5hbWU6KiogVGhlIG5hbWUgb2YgZWFjaCBwb2tlbW9uDQoNCioqVHlwZSAxOioqIERldGVybWluZXMgd2Vha25lc3MvcmVzaXN0YW5jZSB0byBhdHRhY2tzDQoNCioqVHlwZSAyOioqIFNvbWUgcG9rZW1vbiBhcmUgZHVhbCB0eXBlIGFuZCBoYXZlIGEgc2Vjb25kIHR5cGUNCg0KKipUb3RhbDoqKiBTdW0gb2YgYWxsIHN0YXRzIHRoYXQgY29tZSBhZnRlciB0aGlzLCBhIGdlbmVyYWwgZ3VpZGUgdG8gaG93IHN0cm9uZyBhIHBva2Vtb24gaXMNCg0KKipIUDoqKiBIaXQgcG9pbnRzLCBvciBoZWFsdGgsIGRlZmluZXMgaG93IG11Y2ggZGFtYWdlIGEgcG9rZW1vbiBjYW4gd2l0aHN0YW5kIGJlZm9yZSBmYWludGluZw0KDQoqKkF0dGFjazoqKiBUaGUgYmFzZSBtb2RpZmllciBmb3Igbm9ybWFsIGF0dGFja3MgKGVnLiBTY3JhdGNoLCBQdW5jaCkNCg0KKipEZWZlbnNlOioqIFRoZSBiYXNlIGRhbWFnZSByZXNpc3RhbmNlIGFnYWluc3Qgbm9ybWFsIGF0dGFja3MNCg0KKipTUCBBdGs6KiogU3BlY2lhbCBhdHRhY2ssIHRoZSBiYXNlIG1vZGlmaWVyIGZvciBzcGVjaWFsIGF0dGFja3MgKGUuZy4gZmlyZSBibGFzdCwgYnViYmxlIGJlYW0pDQoNCioqU1AgRGVmOioqIFNwZWNpYWwgZGVmZW5zZSwgdGhlIGJhc2UgZGFtYWdlIHJlc2lzdGFuY2UgYWdhaW5zdCBzcGVjaWFsIGF0dGFja3MNCg0KKipTcGVlZDoqKiBEZXRlcm1pbmVzIHdoaWNoIHBva2Vtb24gYXR0YWNrcyBmaXJzdCBlYWNoIHJvdW5kDQoNCioqR2VuZXJhdGlvbjoqKiBUaGUgZ2VuZXJhdGlvbiBvZiBnYW1lcyB3aGVyZSB0aGUgcG9rZW1vbiB3YXMgZmlyc3QgaW50cm9kdWNlZA0KDQoqKkxlZ2VuZGFyeToqKiBTb21lIHBva2Vtb24gYXJlIG11Y2ggcmFyZXIgdGhhbiBvdGhlcnMsIGFuZCBhcmUgZHViYmVkICJsZWdlbmRhcnkiDQoNCioqU3BlY2llczoqKiBhcyBwZXIgbmFtZQ0KDQoqKkZvcm1lOioqIGFzIHBlciBuYW1lDQoNCioqQWJpbGl0eSAxKio6IGFuIGVmZmVjdCBvbiBhIFBva8OpbW9uIHRoYXQgaXMgbm90IGFuIGF0dGFjay4gU29tZSB3aWxsIGJlIGFjdGl2ZSBhbGwgb2YgdGhlIHRpbWUsIHdoaWxlIHNvbWUgeW91IHdpbGwgbmVlZCB0byBjaG9vc2UgdG8gdXNlLg0KDQoqKkFiaWxpdHkgMjoqKiBTb21lIFBva2Vtb24gaGF2ZSBhIHNlY29uZCBhYmlsaXR5DQoNCioqVG90YWw6KiogdG90YWwgb2YgSFAsYXR0YWNrLCBkZWZlbnNlLCBzcGF0dGFjaywgc3BkZWZlbnNlIGFuZCBzcGVlZA0KDQoqKldlaWdodDoqKiB3ZWlnaHQgb2YgdGhlIHBva2Vtb24NCg0KKipIZWlnaHQ6KiogaGVpZ2h0IG9mIHRoZSBwb2tlbW9uDQoNCioqZGV4IDE6KiogdW5rbm93bjogZGV4IGlzIHVzdWFsbHkgc2hvcnQgZm9yICdwb2tlZGV4Jy4gdGhlIGNvbnRlbnRzIG9mIHRoaXMgdmFyaWFibGUgYXJlIG5vdCB1bmRlcnN0b29kDQoNCioqZGV4IDI6KiogYXMgYWJvdmUNCg0KKipjbGFzczoqKiBlYWNoIG1vdmUgaXMgY2xhc3NpZmllZCBhcyBvbmUgb2YgdGhlIDE4IFBva8OpbW9uIHR5cGVzLiBUaGUgZWZmZWN0aXZlbmVzcyBvZiBhIG1vdmUgaXMgZGVwZW5kZW50IG9uIGhvdyBzdXNjZXB0aWJsZSB0aGUgdGFyZ2V0IFBva8OpbW9uJ3MgdHlwZSBpcyB0byB0aGUgbW92ZSdzIHR5cGUuDQoNCioqcGVyY2VudC1tYWxlOioqIHBlcmNlbnRhZ2Ugb2YgbWFsZSBwb2tlbW9uIG9mIHRoaXMgc3BlY2llcy9uYW1lDQoNCioqcGVyY2VudC1mZW1hbGU6KiogcGVyY2VudGFnZSBvZiBmZW1hbGUgcG9rZW1vbiBvZiB0aGlzIHNwZWNpZXMvbmFtZQ0KDQoqKmVnZy1ncm91cDoqKiBjYXRlZ29yaWVzIHdoaWNoIGRldGVybWluZSB3aGljaCBQb2vDqW1vbiBhcmUgYWJsZSB0byBpbnRlcmJyZWVkLiBBIFBva8OpbW9uIG1heSBiZWxvbmcgdG8gZWl0aGVyIG9uZSBvciB0d28gRWdnIEdyb3Vwcy4gDQoNCioqZWdnLWdyb3VwMjoqKiBhcyBhYm92ZQ0KDQoqKkRhdGUuZmlyc3Quc3Bhd25lZDoqKiBkYXRlIHRoZSBwb2tlbW9uIHdhcyBmaXJzdCBkaXNjb3ZlcmVkDQoNCiMjIyBSZWFkIGRhdGENClRoZSBjc3YgZmlsZXMgaGF2ZSBiZWVuIGltcG9ydGVkIHVzaW5nIHRoZSBiYXNlIFIgKnJlYWQuY3N2KiBwYWNrYWdlLCBzcGVjaWZ5aW5nIHRoYXQgbm90IGFsbCBzdHJpbmdzIHNob3VsZCBhdXRvbWF0aWNhbGx5IGJlIGNvbnZlcnRlZCB0byBmYWN0b3JzLiBUaGVyZSBhcmUgbW9yZSBjaGFyYWN0ZXIgdmFyaWFibGVzIHRoYW4gZmFjdG9yIHZhcmlhYmxlcywgc28gdGhlIGZhY3RvcnMgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGNvbnZlcnRlZCBsYXRlci4gVGhlcmUgYXJlIG1hbnkgZW1wdHkgY2VsbHMsIHNvICpuYS5zdHJpbmdzKiB3aWxsIGVuc3VyZSBlbXB0eSBjZWxscyBhcmUgZmlsbGVkIHdpdGggTkEsIHRvIG1ha2UgdGlkeWluZyB0aGUgZGF0YSBlYXNpZXIuIFRvIGluc3BlY3QgdGhlIGRhdGFzZXRzLCAqaGVhZCgpKiBoYXMgYmVlbiB1c2UgdG8gdmlldyB0aGUgZmlyc3QgNiByb3dzIG9mIGVhY2ggZGF0YXNldCBhbmQgKmRpbSgpKiBoYXMgYmVlbiB1c2VkIGZvciBhIHF1aWNrIGdsYW5jZSBhdCB0aGUgZGltZW5zaW9ucyBvZiB0aGUgZGF0YXNldHMuIFBva2Vtb24xIGhhcyA4MDAgcm93cyAob2JzZXJ2YXRpb25zKSBhbmQgMTUgY29sdW1ucyAodmFyaWFibGVzKSBhbmQgUG9rZW1vbjIgaGFzIDEwNjAgcm93cyBhbmQgMjYgY29sdW1ucy4NCmBgYHtyfQ0KI3JlYWQgZGF0YQ0KcG9rZW1vbjEgPC0gcmVhZC5jc3YoJ3Bva2Vtb24gZGF0YTEuY3N2Jywgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBuYS5zdHJpbmdzPSIiKQ0KcG9rZW1vbjIgPC0gcmVhZC5jc3YoJ3Bva2Vtb24gZGF0YTIuY3N2Jywgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBuYS5zdHJpbmdzPSIiKQ0KI3ZpZXcgdGhlIGZpcnN0IDYgcm93cyBvZiBkYXRhDQpoZWFkKHBva2Vtb24xKQ0KaGVhZChwb2tlbW9uMikNCmRpbShwb2tlbW9uMSkNCmRpbShwb2tlbW9uMikNCmBgYA0KDQojIyMgUHJlLW1lcmdlIGRhdGEgdGlkeWluZw0KVGhlIGRhdGFzZXRzIHdpbGwgdW5kZXJnbyBzb21lIGluaXRpYWwgdGlkeWluZyBiZWZvcmUgdGhleSBhcmUgbWVyZ2VkLCB0byBlbnN1cmUgYm90aCBkYXRhc2V0cyBjb250YWluIHRoZSBzYW1lIHVuaXF1ZS4gRGF0YXNldCBvbmUgY29udGFpbnMgZGF0YSBvbiB0aGUgZmlyc3QgNzIxIHBva2Vtb24sIHNvIGRhdGFzZXQgMiB3aWxsIGRyb3AgYW55IHBva2Vtb24gdGhhdCBoYXZlIGEgcG9rZWRleChpbmRleCkgbnVtYmVyIGhpZ2hlciB0aGFuIDcyMS4NCg0KIyMjIFRpZHkgZGF0YXNldCAxDQoNCmBgYHtyIFRJRFkgUE9LRU1PTiAxfQ0KI3JlbW92ZSB0aGUgZmlyc3QgdmFyaWFibGUgYXMgdGhpcyBpcyBpZGVudGljYWwgdG8gdGhlIHBva2RleCBudW1iZXIsIGJvdGggYXJlIG5vdCByZXF1aXJlZA0KcG9rZW1vbjEgPC0gcG9rZW1vbjFbICwgLSgxKV0NCmhlYWQocG9rZW1vbjEpDQojQ0hFQ0sgRk9SIERVUExJQ0FURVMNCmFueShkdXBsaWNhdGVkKHBva2Vtb24xJHBva2VkZXgpKQ0KI3RvIHN0YXJ0IHdpdGgsIHJlbW92ZSBhbnkgcm93cyBjb250YWluaW5nICdtZWdhJ2FzIHRoZXNlIGFyZSBldm9sdmVkIGZvcm1zIG9mIHBva2Vtb24gYW5kIHdlIHdpbGwgb25seSBhbmFseXNlIG9yaWdpbmFsIHBva2Vtb24NCnBva2Vtb24xWy0gZ3JlcCgiTWVnYSIsIHBva2Vtb24xJE5hbWUpLF0NCiNyZW1vdmUgYW55IG90aGVyIGR1cGxpY2F0ZXMgaW4gcG9rZWRleA0KcG9rZW1vbjEgJTw+JSBkaXN0aW5jdChwb2tlZGV4LCAua2VlcF9hbGwgPSBUUlVFKQ0KDQojQ0hFQ0sgRk9SIERVUExJQ0FURVMgLSBub3cgdGhlIGxpc3QgaXMgdW5pcXVlDQphbnkoZHVwbGljYXRlZChwb2tlbW9uMSRwb2tlZGV4KSkNCmBgYA0KIyMjIFRpZHkgZGF0YXNldCAyDQpgYGB7ciBUSURZIFBPS0VNT04gMn0NCiNkcm9wIHBva2Vtb24gaW4gdGhlIHBva2VkZXggZ3JlYXRlciB0aGFuIDcyMiB0byBlbnN1cmUgdGhlIGRhdGFzZXRzIGNvbnRhaW4gdGhlIHNhbWUgcG9rZW1vbiBhbmQgcmVtb3ZlIHRoZSB1bm5lY2Vzc2FyeSBJRCBjb2x1bWJuDQpwb2tlbW9uMiAlPD4lIA0KICBmaWx0ZXIocG9rZWRleDw3MjIpICU+JSANCiAgc2VsZWN0KC1pZCkNCmhlYWQocG9rZW1vbjIpDQpkaW0ocG9rZW1vbjIpDQojcmVtb3ZlIGR1cGxpY2F0ZXMNCnBva2Vtb24yICU8PiUgZGlzdGluY3QocG9rZWRleCwgLmtlZXBfYWxsID0gVFJVRSkNCg0KI0NIRUNLIEZPUiBEVVBMSUNBVEVTDQphbnkoZHVwbGljYXRlZChwb2tlbW9uMiRwb2tlZGV4KSkNCmRpbShwb2tlbW9uMikNCmBgYA0KIyMgTWVyZ2UgdGhlIGRhdGFzZXRzDQpUaGUgZGF0YXNldHMgaGF2ZSBiZWVuIG1lcmdlZCB1c2luZyBhIGZ1bGwgam9pbiB3aXRoIHBva2VkZXggYXMgdGhlIHByaW1hcnkga2V5LiBUaGUgcG9rZWRleCBhY3RzIGxpa2UgYW4gaW5kZXgsIHdpdGggZWFjaCB1bmlxdWUgcG9rZW1vbiBoYXZpbmcgYSByZWZlcmVuY2Ugb24gdGhlIHBva2VkZXguIFRoZSBmdWxsIGpvaW4gaGFzIGJlZW4gdXNlZCB0byByZXR1cm4gYWxsIHJvd3MgYW5kIGFsbCBjb2x1bW5zIGZyb20gYm90aCBwb2tlbW9uMSBhbmQgcG9rZW1vbjIgZGF0YXNldHMuIElmIHRoZXJlIHRoZXJlIGhhcHBlbnMgdG8gYmUgbm8gbWF0Y2hpbmcgdmFsdWUsIHRoZXJlIHdpbGwgYmUgYW4gTkEgcmV0dXJuZWQgZm9yIHRoZSBvbmUgbWlzc2luZy4NCmBgYHtyIE1FUkdFfQ0KI0pPSU4gREFUQVNFVFMNCnBva2Vtb25fZGYgPC0gcG9rZW1vbjEgJT4lIA0KICBmdWxsX2pvaW4ocG9rZW1vbjIsIGJ5ID0gJ3Bva2VkZXgnKQ0KZGltKHBva2Vtb25fZGYpDQpgYGANCiMjIFVuZGVyc3RhbmQgDQoNClRoZSAqc3RyKCkqIGZ1bmN0aW9ucyBzaG93cyBhbGwgdGhlIHR5cGVzIG9mIGRhdGEuIEFzIHdlIHVzZWQgKnN0cmluZ2FzZmFjdG9ycz1GQUxTRSogd2hlbiByZWFkaW5nIHRoZSBkYXRhLCB0aGVyZSBhcmUgbm8gZmFjdG9ycyBpbiB0aGlzIGxpc3QsIGhvd2V2ZXIgVHlwZSBzaG91bGQgYmUgYW4gb3JkZXJlZCBmYWN0b3IsIGFzIGNlcnRhaW4gdHlwZXMgYXJlIHN0cm9uZ2VyIHRoYW4gb3RoZXJzLCBhbmQgZGF0ZSB3aWxsIGFsc28gbmVlZCB0byBiZSBjb252ZXJ0ZWQuIFRoZSAqc3VtbWFyeSgpKiBmdW5jdGlvbiBzaG93cyB0aGUgcmFuZ2Ugb2YgZWFjaCB2YXJpYWJsZSwgd2hlcmUgaXQgaXMgbnVtZXJpYywgdGhlIG1pbiwgbWF4LCBtZWRpYWwgYW5kIHF1YXJ0aWxlcyAxIGFuZCAzLiBXaGVyZSBpdCdzIGEgY2hhcmFjdGVyIHZhcmlhYmxlLCB0aGUgY2xhc3MgYW5kIG1vZGUgYXJlIHNob3duLg0KDQpgYGB7cn0NCnN0cihwb2tlbW9uX2RmKQ0Kc3VtbWFyeShwb2tlbW9uX2RmKQ0KYGBgDQojIyBhcHBseSBkYXRhIGNvbnZlcnNpb25zDQpUeXBlIDEgaGFzIGJlZW4gY29udmVydGVkIHRvIGEgZmFjdG9yIGFuZCB0aGVuIHRoZSBvcmRlcmVkIGxldmVscyBoYXZlIGJlZW4gYXBwbGllZC4gRGF0ZS5maXJzdC5zcGF3bmVkIGhhcyBiZWVuIGNvbnZlcnRlZCBmcm9tIGNoYXJhY3RlciB0byBkYXRlLiANCmBgYHtyfQ0KI29yZGVyIHZhcmlhYmxlcyB0aGF0IGhhdmUgYSBoaWVyYXJjaHkNCnBva2Vtb25fZGYkdHlwZTEgPC0gIGFzLmZhY3Rvcihwb2tlbW9uX2RmJHR5cGUxKQ0Kc3RyKHBva2Vtb25fZGYkdHlwZTEpDQoNCiNvcmRlciB2YXJpYWJsZXMgdGhhdCBoYXZlIGEgaGllcmFyY2h5DQpwb2tlbW9uX2RmJHR5cGUxIDwtICBmYWN0b3IocG9rZW1vbl9kZiR0eXBlMSwNCiAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPWMoJ0RyYWdvbicsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICdGYWlyeScsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnV2F0ZXInLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnU3RlZWwnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRmlnaHRpbmcnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRGFyaycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICdGbHlpbmcnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRmlyZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICdHaG9zdCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICdHcm91bmQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTm9ybWFsJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1BzeWNoaWMnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRWxlY3RyaWMnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUG9pc29uJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0dyYXNzJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1JvY2snLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQnVnJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0ljZScpLA0KICAgICAgICAgICAgICAgICAgICBvcmRlcmVkPVRSVUUpDQoNCiNjb252ZXJ0IGRhdGUgZnJvbSBjaGFyYWN0ZXIgdG8gZGF0ZQ0KcG9rZW1vbl9kZiREYXRlLmZpcnN0LnNwYXduZWQgPC0gYXMuRGF0ZShwb2tlbW9uX2RmJERhdGUuZmlyc3Quc3Bhd25lZCkNCnN0cihwb2tlbW9uX2RmKQ0KDQoNCmBgYA0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIA0KDQpUbyBjaGVjayBpZiB0aGlzIGRhdGEgaXMgdGlkeSwgY29tcGFyaXNvbnMgYmV0d2VlbiB0aGUgc2ltaWxhciB2YXJpYWJsZXMgaGF2ZSBiZWVuIG1hZGUuIEZpcnN0bHkgKmlkZW50aWNhbCgpKiBpcyB1c2VkIHRvIHNlZSBpZiB0aGUgdHdvIGNvbHVtcyBhcmUgaWRlbnRpY2FsIG9yIG5vdCwgaWYgbm90IHRoZW4gKndoaWNoKCkqIGlzIHVzZWQgdG8gc2VlIHdoaWNoIG9ic2VydmF0aW9ucyBhcmUgZGlmZmVyZW50LiBBbGwgb2YgdGhlIHNpbWlsYXIgdmFyaWFibGVzIGhhdmUgYmVlbiAyIGFuZCAyNCB2YXJpYWJsZXMsIHNvIGEgZGVjaXNpb24gdG8ga2VlcCB0aGUgdmFyaWFibGVzIGZyb20gcG9rZW1vbjIgaGFzIGJlZW4gbWFkZS4NClNvbWUgdmFyaWFibGVzIGhhdmUgYmVlbiByZW5hbWVzIHRvIGF2b2lkIGNvbmZ1c2lvbiAoZS5nLiB0aGUgdmFyaWFibGUgJ2NsYXNzJyBjb3VsZCBiZSBjb25mdXNlZCB3aXRoICpjbGFzcygpKikNCkZvcm1lIGhhcyBiZWVuIGNoYW5nZWQgdG8gZm9ybSANCkFueSBpbnN0YW5jZXMgb2YgJ1Bva8ODwqltb24nIGhhdmUgYmVlbiBkcm9wcGVkIGZyb20gdGhlIGNvbHVtbiBjbGFzcy9wb2tlY2xhc3MNCg0KYGBge3J9DQojY29tcGFyZSBzaW1pbGFyIHZhcmlhYmxlcw0KaWRlbnRpY2FsKHBva2Vtb25fZGZbWydOYW1lJ11dLHBva2Vtb25fZGZbWydzcGVjaWVzJ11dKQ0KcG9rZW1vbl9kZlt3aGljaChwb2tlbW9uX2RmJE5hbWUgIT0gcG9rZW1vbl9kZiRzcGVjaWVzKSwgXQ0KDQppZGVudGljYWwocG9rZW1vbl9kZltbJ1R5cGUuMSddXSxwb2tlbW9uX2RmW1sndHlwZTEnXV0pDQpwb2tlbW9uX2RmW3doaWNoKHBva2Vtb25fZGYkVHlwZS4xICE9IHBva2Vtb25fZGYkdHlwZTEpLCBdDQoNCmlkZW50aWNhbChwb2tlbW9uX2RmW1snVHlwZS4xJ11dLHBva2Vtb25fZGZbWyd0eXBlMiddXSkNCnBva2Vtb25fZGZbd2hpY2gocG9rZW1vbl9kZiRUeXBlLjIgIT0gcG9rZW1vbl9kZiR0eXBlMiksIF0NCg0KaWRlbnRpY2FsKHBva2Vtb25fZGZbWydIUCddXSxwb2tlbW9uX2RmW1snaHAnXV0pDQpwb2tlbW9uX2RmW3doaWNoKHBva2Vtb25fZGYkSFAgIT0gcG9rZW1vbl9kZiRocCksIF0NCg0KaWRlbnRpY2FsKHBva2Vtb25fZGZbWydBdHRhY2snXV0scG9rZW1vbl9kZltbJ2F0dGFjayddXSkNCnBva2Vtb25fZGZbd2hpY2gocG9rZW1vbl9kZiRBdHRhY2sgIT0gcG9rZW1vbl9kZiRhdHRhY2spLCBdDQoNCmlkZW50aWNhbChwb2tlbW9uX2RmW1snRGVmZW5zZSddXSxwb2tlbW9uX2RmW1snZGVmZW5zZSddXSkNCnBva2Vtb25fZGZbd2hpY2gocG9rZW1vbl9kZiREZWZlbnNlICE9IHBva2Vtb25fZGYkZGVmZW5zZSksIF0NCg0KaWRlbnRpY2FsKHBva2Vtb25fZGZbWydTcC4uQXRrJ11dLHBva2Vtb25fZGZbWydzcGF0dGFjayddXSkNCnBva2Vtb25fZGZbd2hpY2gocG9rZW1vbl9kZiRTcC4uQXRrICE9IHBva2Vtb25fZGYkc3BhdHRhY2spLCBdDQoNCmlkZW50aWNhbChwb2tlbW9uX2RmW1snU3AuLkRlZiddXSxwb2tlbW9uX2RmW1snc3BkZWZlbnNlJ11dKQ0KcG9rZW1vbl9kZlt3aGljaChwb2tlbW9uX2RmJFNwLi5EZWYgIT0gcG9rZW1vbl9kZiRzcGRlZmVuc2UpLCBdDQoNCmlkZW50aWNhbChwb2tlbW9uX2RmW1snU3BlZWQnXV0scG9rZW1vbl9kZltbJ3NwZWVkJ11dKQ0KcG9rZW1vbl9kZlt3aGljaChwb2tlbW9uX2RmJFNwZWVkICE9IHBva2Vtb25fZGYkc3BlZWQpLCBdDQoNCmlkZW50aWNhbChwb2tlbW9uX2RmW1snVG90YWwnXV0scG9rZW1vbl9kZltbJ3RvdGFsJ11dKQ0KcG9rZW1vbl9kZlt3aGljaChwb2tlbW9uX2RmJFRvdGFsICE9IHBva2Vtb25fZGYkdG90YWwpLCBdDQoNCiNkcm9wIHVubmVjZXNzYXJ5IGNvbHVtbnMgLSBrZWVwIHRoZSB2YWx1ZXMgZnJvbSBwb2tlbW9uIGRhdGEyDQpwb2tlbW9uX2RmMiA8LSBzZWxlY3QocG9rZW1vbl9kZiwgLU5hbWUsIC1IUCwgLUF0dGFjaywgLURlZmVuc2UsIC1TcC4uQXRrLCAtU3AuLkRlZiwgLVNwZWVkLCAtVG90YWwsIC1kZXgxLCAtZGV4MiwgLVR5cGUuMSwgLVR5cGUuMikNCg0KI3JlbmFtZSBjbGFzcyB0byBhdm9pZCBjb25mdXNpb24gd2l0aCBjbGFzcygpDQpwb2tlbW9uX2RmMiAlPD4lIA0KICByZW5hbWUocG9rZWNsYXNzID0gY2xhc3MpDQoNCiNyZW5hbWUgJ2Zvcm1lJyB0byBmb3JtDQpwb2tlbW9uX2RmMiAlPD4lIA0KICByZW5hbWUoZm9ybSA9IGZvcm1lKQ0KDQojcmVtb3ZlIHNwZWNpYWwgY2hhcmFjdGVycyBmcm9tIGNsYXNzIGNvbHVtbg0KcG9rZW1vbl9kZjIkcG9rZWNsYXNzICU8PiUgc3RyX3JlcGxhY2UoIlBva8ODwqltb24iLCIiKQ0KaGVhZChwb2tlbW9uX2RmMikNCmRpbShwb2tlbW9uX2RmMikNCnN0cihwb2tlbW9uX2RmMikNCmBgYA0KDQojIwlUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIElJIA0KQSBuZXcgY29sdW1uIGhhcyBiZWVuIGNyZWF0ZWQgdXNpbmcgKm11dGF0ZSgpKiB0byBhZGQgdG9nZXRoZXIgYXR0YWNrIGFuZCBzcGF0dGFjayBmb3IgZWFjaCBwb2tlbW9uLCBpbiBhIG5ldyBjb2x1bW4gY2FsbGVkICd0b3RhbGF0dGFjaycNCmBgYHtyfQ0KI2NyZWF0ZSB0b3RhbCBhdHRhY2sgcG9pbnRzIGNvbHVtbg0KbXV0YXRlKHBva2Vtb25fZGYyLCB0b3RhbGF0dGFjayA9IGF0dGFjaytzcGF0dGFjaykgDQpgYGANCg0KIyMJU2NhbiBJIA0KDQoqY29sU3VtcygpKiBoYXMgYmVlbiB1c2VkIHRvIHNlZSBob3cgbWFueSBtaXNzaW5nIHZhbHVlcyBhcmUgaW4gZWFjaCBjb2x1bW4uIEF0IHRoaXMgc3RhZ2UsIDcgY29sdW1ucyBoYXZlIG1pc3NpbmcgdmFsdWVzLiBUaGUgcGVyY2VudGFnZSBvZiBmZW1hbGUgYW5kIG1hbGUgdmFyaWFibGVzIGhhdmUgYmVlbiBpbXB1dGVkIHdpdGggdGhlIG1lYW4sIHVzaW5nICppbXB1dGUoKSoNClRoZSB2YXJpYWJsZXMgdHlwZTIsIGFiaWxpdHksIHByZS5ldm9sdXRpb24gYW5kIGVnZy5ncm91cDIgaGF2ZSBibGFuayB2YWx1ZXMgaW4gc29tZSBvYnN2ZXJhdGlvbnMsIGJ1dCB0aGlzIGlzIG5vdCBtaXNzaW5nIGRhdGEsIGFzIG5vdCBhbGwgcG9rZW1vbiBoYXZlIHRoZXNlIGF0dHJpYnV0ZXMuIFdoZXJlIHRoZXJlIGluIGFuIE5BIGluIHRoZXNlIG9ic2VydmF0aW9ucywgd2Ugd2lsbCByZXBsYWNlIHRoZSBOQSB3aXRoIGEgc3RyaW5nIHRvIG1ha2UgaXQgY2xlYXIgdGhhdCB0aGUgYXR0cmlidXRlIGlzIG5vdCBhcHBsaWJsZSByYXRoZXIgdGhhbiBtaXNzaW5nLiANCkFiaWxpdHlIIHdpbGwgYmUgcmVwbGFjZWQgd2l0aCB0aGUgbW9kZSwgb3IgbW9zdCBjb21tb25seSBhcHBlYXJpbmcgYWJpbGl0eUgNCmBgYHtyfQ0KI0xvb2sgZm9yIG1pc3NpbmcgdmFsdWVzDQpjb2xTdW1zKGlzLm5hKHBva2Vtb25fZGYyKSkNCg0KI2ltcHV0ZSBtaXNzaW5nIHZhbHVlcyB3aXRoIG1lYW4NCnBva2Vtb25fZGYyJHBlcmNlbnQubWFsZSAlPD4lIGltcHV0ZShwb2tlbW9uX2RmMiRwZXJjZW50Lm1hbGUsIGZ1biA9IG1lYW4pDQpwb2tlbW9uX2RmMiRwZXJjZW50LmZlbWFsZSAlPD4lIGltcHV0ZShwb2tlbW9uX2RmMiRwZXJjZW50LmZlbWFsZSwgZnVuID0gbWVhbikNCg0KI3R5cGUgMiwgYWJpbGl0eSAyLCBwcmUuZXZvbHV0aW9uIGFuZCBhbmQgZWdnIGdyb3VwIDIgYWxsIGhhdmUgb3ZlciBoYWxmIHRoZSBvYnNlcnZhdGlvbnMgbWlzc2luZyBob3dldmVyIHRoaXMgaXMgbm90IG1pc3NpbmcgZGF0YSwgdGhlc2UgcG9rZW1vbiBkbyBub3QgaGF2ZSB0aGVzZSBhdHRyaWJ1dGVzIGFuZCB0aGVzZSBjb2x1bW5zIHNob3VsZCBub3QgYmUgZHJvcHBlZC4gQ2VsbHMgd2lsbCBiZSBmaWxsZWQgd2l0aCBhIG5ldyBzdHJpbmcNCnBva2Vtb25fZGYyJHR5cGUyICU8PiUgcmVwbGFjZV9uYSgibm8gdHlwZSAyIikNCnBva2Vtb25fZGYyJGFiaWxpdHkyICU8PiUgcmVwbGFjZV9uYSgibm8gYWJpbGl0eSAyIikNCnBva2Vtb25fZGYyJHByZS5ldm9sdXRpb24gJTw+JSByZXBsYWNlX25hKCJubyBwcmUtZXZvbHV0aW9uIikNCnBva2Vtb25fZGYyJGVnZy5ncm91cDIgJTw+JSByZXBsYWNlX25hKCJubyBlZ2cgZ3JvdXAgMiIpDQoNCiNhYmlsaXR5IEggd2lsbCBiZSByZXBsYWNlZCB3aXRoIHRoZSBtb2RlDQpwb2tlbW9uX2RmMiRhYmlsaXR5SCAlPD4lIGltcHV0ZShwb2tlbW9uX2RmMiRhYmlsaXR5SCwgZnVuPSBtb2RlKQ0KDQojTG9vayBhZ2FpbiBmb3IgbWlzc2luZyB2YWx1ZXMNCmNvbFN1bXMoaXMubmEocG9rZW1vbl9kZjIpKQ0KYGBgDQoNCg0KIyMJU2NhbiBJSQ0KQXMgdGhlcmUgYXJlIG1hbnkgbnVtZXJpYyB2YXJpYWJsZXMsIGEgbXVsdGl2YXJpYXRlIGFuYWx5c2lzIGhhcyBiZWVuIGNob3Nlbi4gRmlyc3RseSwgYSBzdWJzZXQgb2Ygb25seSBudW1lcmljIHZhcmlhYmxlcyBpcyBtYWRlLiBBcyBhbGwgbWlzc2luZyB2YWx1ZXMgaGF2ZSBiZWVuIHRha2VuIGNhcmUgb2YsIHRoZSBhZGRpdGlvbiBzdGVwIG9mIHJlbW92aW5nIG1pc3NpbmcgdmFsdWVzIGlzIG5vdCBuZWVkZWQuICpNVk4qIGlzIHVzZWQgdG8gZmluZCBhbmQgZXhjbHVkZSB0aGUgbXV0bGl2YXJpYXRlIG91dGxpZXJzIGFuZCByZXR1cm4gdGhlIG9ic2VydmF0aW9uIG51bWJlcnMgb2YgdGhlIG91dGxpZXJzLiBUaGUgZGF0YSBpcyB0aGVuIHN1YnNldCBhZ2FpbiB0byBleGNsdWRlIHRoZSBvYnNlcnZhdGlvbnMgdGhhdCBjb250YWluIHRoZSBvdXRsaWVycy4NCmBgYHtyfQ0KIyBTdWJzZXQgdGhlIGRhdGFzZXQgdG8gcmVsZXZhbnQgbnVtZXJpYyB2YXJpYWJsZXMNCnBva2Vtb25fc3ViIDwtIHBva2Vtb25fZGYyICU+JSBzZWxlY3QoaHAsIGF0dGFjayxkZWZlbnNlLCBzcGF0dGFjaywgc3BkZWZlbnNlLCBzcGVlZCwgdG90YWwpIA0KZGltKHBva2Vtb25fc3ViKQ0KIyBGaW5kIGFuZCBleGNsdWRlIHRoZSBtdWx0aXZhcmlhdGUgb3V0bGllcnMgDQpwb2tlcmVzdWx0cyA8LSBwb2tlbW9uX3N1YiAlPiUgDQogIE1WTjo6bXZuKG11bHRpdmFyaWF0ZU91dGxpZXJNZXRob2QgPSAicXVhbiIsIA0KICAgICAgICAgICBzaG93T3V0bGllcnMgPSBUUlVFKQ0KcG9rZXJlc3VsdHMkbXVsdGl2YXJpYXRlT3V0bGllcnMNCiNyZXR1cm5zIHRoZSBvYnNlcnZhdGlvbiBudW1iZXJzIG9mIHRoZSBvdXRsaWVycyBhbmQgdGhlbiBjb252ZXJ0cyBmcm9tIGNoYXJhY3RlciB0byBudW1lcmljDQpwb2tlbW9uX291dGxpZXJzIDwtIHBva2Vtb25fc3ViW2MoYXMubnVtZXJpYyhwb2tlcmVzdWx0cyRtdWx0aXZhcmlhdGVPdXRsaWVyc1tbIk9ic2VydmF0aW9uIl1dKSksIF0NCg0KIyAjIHN1YnNldCB0aGUgZGF0YXNldCBieSBpbmNsdWRpbmcgcm93cyBjb250YWluIGluIHRoZSBzcGVjaWZpZWQgb2JzZXJ2YXRpb24gbnVtYmVycyANCnBva2Vtb25fY2xlYW4gPC0gcG9rZW1vbl9zdWJbLWMoYXMubnVtZXJpYyhwb2tlcmVzdWx0cyRtdWx0aXZhcmlhdGVPdXRsaWVyc1tbIk9ic2VydmF0aW9uIl1dKSksIF0NCmRpbShwb2tlbW9uX2NsZWFuKQ0KZGltKHBva2Vtb25fb3V0bGllcnMpDQpkaW0ocG9rZW1vbl9zdWIpDQpgYGANCg0KIyMJVHJhbnNmb3JtIA0KVGhlIGhpc3RvZ3JhbSBvZiBocCBpcyB2ZXJ5IHJpZ2h0IHNrZXdlZC4gQSBib3gtY294IHRyYW5zZm9ybWF0aW9uIGhhcyBiZWVuIGFwcGxpZWQsIHdoZXJlIHRoZSBsYW1iYSBpcyBhdXRvbWF0aWNhbGx5IGZvdW5kIGFuZCBhcHBsaWVkLiBBZnRlciB0aGUgdHJhbnNmb3JtYXRpb24sIHRoZSBzaGFwZSBvZiB0aGUgaGlzdG9ncmFtIGlzIHNsaWdodGx5IG1vcmUgbm9ybWFsaXNlLCBob3dldmVyIHRoZXJlIGlzIG5vd2Egc2xpZ2h0IGxlZnQgc2tldy4NCmBgYHtyfQ0KI2NyZWF0ZSBhIGhpc3RvZ3JhbQ0KaGlzdChwb2tlbW9uX2RmMiRocCkNCiNBcHBseSBCb3gtQ294IHRyYW5zZm9ybWF0aW9uIA0KYm94Y294X2hwIDwtIEJveENveChwb2tlbW9uX2RmMiRocCwgbGFtYmRhID0gImF1dG8iKQ0KYXR0cihib3hjb3hfaHAsIHdoaWNoID0gImxhbWJkYSIpDQpoaXN0KGJveGNveF9ocCkNCmBgYA0KDQojI1JlZmVyZW5jZXMNCg0KQmlvc3RhcnMuICgyMDIwLCAwMiAwMSkuIFF1ZXN0aW9uOiBGaW5kIG1pc21hdGNoIGluIHR3byBjb2x1bW5zIGluIGEgZGF0YSBmcmFtZSBpbiBSLiBSZXRyaWV2ZWQgZnJvbSBCaW9zdGFyczsgYmlvaW5mb3JtYXRpY3MgZXhwbGFpbmVkOiBodHRwczovL3d3dy5iaW9zdGFycy5vcmcvcC8xODA0NTEvDQoNCkRhdGFOb3ZpYS4gKDIwMjEsIDAxIDAyKS4gSWRlbnRpZnkgYW5kIFJlbW92ZSBEdXBsaWNhdGUgRGF0YSBpbiBSIC4gUmV0cmlldmVkIGZyb20gRGF0YU5vdmlhOiBodHRwczovL3d3dy5kYXRhbm92aWEuY29tL2VuL2xlc3NvbnMvaWRlbnRpZnktYW5kLXJlbW92ZS1kdXBsaWNhdGUtZGF0YS1pbi1yLw0KDQpGb250ZXMsIFIuICgyMDIxLCAwMiAxMikuIFBva8OpbW9uOiBFdmVyeSBFbGVtZW50YWwgVHlwZSwgT2ZmaWNpYWxseSBSYW5rZWQuIFJldHJpZXZlZCBmcm9tIFRoZWdhbWVyOiBodHRwczovL3d3dy50aGVnYW1lci5jb20vcG9rZW1vbi1lbGVtZW50YWwtdHlwZXMtcmFua2VkLW9mZmljaWFsbHkvDQoNCmludGVsbGlQYWF0LiAoMjAyMSwgMDIgMTEpLiBDaGFuZ2UgdGhlIEJsYW5rIENlbGxzIHRvIOKAnE5B4oCdLiBSZXRyaWV2ZWQgZnJvbSBpbnRlbGxpcGFhdDogaHR0cHM6Ly9pbnRlbGxpcGFhdC5jb20vY29tbXVuaXR5LzI3MTAzL2NoYW5nZS10aGUtYmxhbmstY2VsbHMtdG8tbmENCg0KV2lja2hhbSwgSC4gKDIwMjEsIDAyIDExKS4gUmVwbGFjZSBOQXMgd2l0aCBzcGVjaWZpZWQgdmFsdWVzLiBSZXRyaWV2ZWQgZnJvbSB0aWR5cjogaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9yZXBsYWNlX25hLmh0bWwNCg0K