import numpy  as np
import pandas as pd

% matplotlib inline
from matplotlib import pyplot as plt

from sklearn.metrics import accuracy_score, precision_score, recall_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

"""
Explanation: Predicting Pokemon Type Using Damage Stats
Data originally from Kaggle datasets: Pokemon with stats.
From Kaggle's description:

This data set includes 721 Pokemon, including their number, name, first and second type, and basic stats.
This are the raw attributes that are used for calculating how much damage an attack will do in the games.


1 Imports
Apart from the usual imports (i.e. numpy, pandas and matplotlib), we will be importing:

accuracy_score, precision_score and recall_score from sklearn's metrics module, for model evaluation
train_test_split, a method from sklearn.model_selection that conveniently partitions the raw data into training and test sets 
DecisionTreeClassifier from sklearn.tree, a classifier that we will use to exemplify overfitting with and without training and test split.
End of explanation
"""


data = pd.read_csv('../data/pokemon.csv')

"""
Explanation: 2 About the data
We will import the Pokemon data from the data folder, placed in the root directory for the unit, using the read_csv method from pandas.
End of explanation
"""


data.columns = data.columns.str.upper()

"""
Explanation: For convenience, we will rename all columns to upper case, so we don't have to remember what is upper or lower case in the future.
End of explanation
"""


data = data.set_index('NAME')
data.index = data.index.str.replace(".*(?=Mega|Primal|Origin|Therian|Land|Incarnate)", "")
data = data.drop(['#'], axis=1)

"""
Explanation: We will also change the index of the dataframe to be the Pokemon's name, and we will use some magic to make names look nicer.
End of explanation
"""


most_powerful = data.sort_values('TOTAL', ascending=False)
most_powerful.head(n=3)

"""
Explanation: We are ready to take a look at the data for the first time! 
Instead of simply calling head on the dataframe, let's precede it with sort_values, to get the Top 3 most powerful Pokemon in the dataset.
End of explanation
"""


most_powerful_by_type = most_powerful.drop_duplicates(subset=['TYPE 1'], keep='first')
most_powerful_by_type

"""
Explanation: In doubt, [this](https://bulbapedia.bulbagarden.net/wiki/Rayquaza_(Pok%C3%A9mon) is a Mega Rayquaza. But what about the most powerful Pokemon by type (Type 1)?
End of explanation
"""


columns = ['ATTACK', 'DEFENSE', 'SPEED', 'TYPE 1']
data_clf = data[columns]

"""
Explanation: 3 Pre-processing data
We will start by selecting the features we want to use and the label.
We will try to predict the Pokemon type using three main features to represent the Pokemon entity: 

Attack 
Defence
Speed.
End of explanation
"""


print("The dataset contains %s rows and %s columns." % data.shape)
print("The dataset columns are: %s."% data.columns.values)
data_clf.describe()

"""
Explanation: Now, briefly describing the raw dataset.
End of explanation
"""


X = data_clf.drop(['TYPE 1'], axis=1)
y = data_clf['TYPE 1']

"""
Explanation: Time to separate our features from the labels, and we're ready to train a simple model.
End of explanation
"""


clf = DecisionTreeClassifier(random_state=0)

"""
Explanation: 3 Training and testing a model in a single dataset
We want to use a Decision Tree classifier.
End of explanation
"""


model_using_all_data = clf.fit(X, y)

y_pred = model_using_all_data.predict(X)

accuracy_using_all_data = accuracy_score(y, y_pred)
print("The accuracy score of the model is: %s." % accuracy_using_all_data)

results_using_all_data = data
results_using_all_data['PREDICTED'] = y_pred

failures = results_using_all_data['TYPE 1'] != results_using_all_data['PREDICTED']
results_using_all_data[failures].head(n=10)

"""
Explanation: Using the same dataset for training and testing our model, we get a remarkable accuracy score!
End of explanation
"""


X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

print("The training dataset contains %s rows and %s columns." % X_train.shape)
print("The test dataset contains %s rows and %s columns." % X_test.shape)

"""
Explanation: 4 Using training and test sets
We're going to leave 20% of the total data aside for testing, that we will not use to train our model.
End of explanation
"""


model_using_test_data = clf.fit(X_train, y_train)

y_pred = model_using_test_data.predict(X_test)

accuracy_using_test_data = accuracy_score(y_test, y_pred)
print("The accuracy score of the model for previously unseen data is: %s." % accuracy_using_test_data)

"""
Explanation: Now, we will use one partition for training and the other for testing or evaluating model performance on previously unseen data.
End of explanation
"""


