To see if legendary Pokémon can be differentiated from non-legendary, and discover the underlying features that separate legendary Pokémon from their less esteemed counterparts.
- pokemon_classifier.py - full code for classifier
- misclassifications.py - reverse engineering code to discover the misclassified Pokémon to look into why they were misclassified
- pokemon.csv - CSV file of constructed Pokémon data
- model.pkl - final SVM model for Pokémon classification
809 unique Pokémon (generations 1-7), 80 of them considered legendary
Features: HP, Attack, Defense, Special Attack, Special Defense, Speed, Height, Weight
-
Used Pandas read_html function to scrape table of Pokémon and their attributes from the Pokémon Database
- Reset dataframe index to be the Pokédex number and dropped different sprites of the same Pokémon
- Separated 'Type' category into 'Type 1' and 'Type 2' when necessary, and dropped 'Total' category (although 'Type' categories ultimately not used for modeling)
- Fixed special Pokémon name cases for API calls to work
-
Leveraged the PokéAPI for additional attributes
- Got the URLs for all of the Pokémon via API call
- Used the API to grab each Pokémon's height and weight and converted them to meters and kilograms, respectively
- Concatenated those values to the Pokédex dataframe and dropped all Pokémon that were not included in the PokéAPI
-
Utilized BeautifulSoup library to scrape heights and weights of any remaining Pokémon of interest from Serebii
-
Got list of legendary Pokémon from scraping Serebii using BeautifulSoup library
- Marked all Pokémon in the dataframe as either legendary (1) or non-legendary (0)
- Correlation heatmap of Pokémon features
- Overlapping histograms showing the distributions of all features for non-legendary vs. legendary Pokémon
-
Explanatory variables (aforementioned 8 features) vs. response variable of legendary or not
-
Performed SMOTE on training data to account for class imbalance since only about 10% of all Pokémon in the data were legendary — synthesized more elements for the legendary class
-
Trained and tested 4 classification machine learning models — Decision Tree, Random Forest, XGBoost, and SVM:
Model Accurary Precision Recall F1-Score Decision Tree 0.90 0.50 0.62 0.56 Random Forest 0.95 0.72 0.81 0.76 XGBoost 0.96 0.74 0.88 0.80 SVM 0.96 0.78 0.88 0.82 -
Ran Grid Search on top-performing SVM model with C values ranging from 0.001 to 1000 (moving one decimal place to the right for each value in that range) and for all possible kernel values
-
Optimal parameters were C = 1000 and kernel = rbf (radial)*
-
Accuracy, Precision, and F1-Score all increased, while Recall dropped:
Model Accurary Precision Recall F1-Score SVM (before) 0.96 0.78 0.88 0.82 SVM (after) 0.97 0.92 0.75 0.83
Final model overall displayed 97% accuracy
- Because SVM does not have feature importance with the rbf kernel, I ran a grid search on my XGBoost model, since it was also very good, and calculated the feature importance on that model
- Feature importance seems to match correlations with ‘Legendary’ from heatmap, with 'Special Attack' appearing to have the most influence
Insight into Misclassifications - misclassifications.py
- Misclassified Pokémon evidently displayed characteristics similar to the classes they were identified as members of, i.e. non-legendary Pokémon having traits more similar to the average legendary Pokémon and vice versa






