# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Data wrangling

# ## import data

import pandas as pd
import numpy as np

url = "https://raw.githubusercontent.com/lopez-isaac/project-data-sets/master/world%202018%20lol.csv"
main_df = pd.read_csv(url)

main_df.head()

# +
### If importing locally

#path = "/Users/isaaclopez/Downloads/world 2018 lol.csv"
#main_df = pd.read_csv(path)
# -

# ## Clean up data frame

#remove display limits
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)

# #copy data
clean_up = main_df

# +
#drop timebased or Unnecessary columns
drop = ["gameid","url","league","split","date","week","game","patchno","playerid","player","team",]

clean_up = main_df.drop(columns=drop)
# -

#check
clean_up.head()

#check for null values
clean_up.isnull().sum()

# +
## Fix nan values

#fill nan values with either 1 or 0 
fill_list =[1,0]
clean_up['fbaron'] = clean_up['fbaron'].fillna(pd.Series(np.random.choice(fill_list, size=len(clean_up.index))))

#fill nan values with the column mean
clean_up["fbarontime"]  = clean_up["fbarontime"].fillna((clean_up["fbarontime"].mean()))

#fill nan values with either 1 or 0 
clean_up["herald"] = clean_up["herald"].fillna(pd.Series(np.random.choice(fill_list,size=len(clean_up.index))))

#drop the column mostly nan values
clean_up = clean_up.drop(columns=["heraldtime"])
# -

#check
clean_up.isnull().sum()

clean_up.head()

clean_up.dtypes

# +
#change data type object to int

object_int = ["doubles","triples","quadras","pentas"]

for x in object_int:
    clean_up[x] = clean_up[x].replace(' ', np.NaN)
    #fill nan values with the column mode
    clean_up[x]  = clean_up[x].fillna(clean_up[x].mode()[0])
    clean_up[x] = clean_up[x].astype(float)
# -

clean_up["dmgshare"] = clean_up["dmgshare"].replace(' ', np.NaN)
clean_up["dmgshare"] = clean_up["dmgshare"].astype(float)
clean_up["dmgshare"]  = clean_up["dmgshare"].fillna((clean_up["dmgshare"].mean()))

clean_up["earnedgoldshare"] = clean_up["earnedgoldshare"].replace(' ', np.NaN)
clean_up["earnedgoldshare"] = clean_up["earnedgoldshare"].astype(float)
clean_up["earnedgoldshare"]  = clean_up["earnedgoldshare"].fillna((clean_up["earnedgoldshare"].mean()))

#drop to many blanks
clean_up["visiblewardclearrate"].value_counts()

#drop to many blanks
clean_up["invisiblewardclearrate"].value_counts()

clean_up = clean_up.drop(columns=["visiblewardclearrate","invisiblewardclearrate"])

clean_up.isnull().sum()

# +
#need to drop towers destoryed causing indirect leakage
#teamtowerkills             0
#opptowerkills

clean_up = clean_up.drop(columns=["opptowerkills","teamtowerkills"])
# -

# # Feature Engineering 

feat_engin = clean_up
print(clean_up.shape)
clean_up.head()

feat_engin["blue_side"] = (feat_engin["side"] == "Blue")

feat_engin.head()

blue_side = {True:1,False:0}
feat_engin["blue_side"] = feat_engin["blue_side"].replace(blue_side)

#def blue_victory(result,side):
    #if result == side:
        #return 1
    #else:
        #return 0

Tournament = feat_engin

# # machine learning, predict match winner

# ## majority value baseline

target = Tournament["result"]

#unique value percentages for target 
target.value_counts(normalize=True)

# ## train, validation, test split

from sklearn.model_selection import train_test_split

# +
#train and test split 85% and 15% split
train, test = train_test_split(Tournament, train_size=.85, test_size=.15,
                              stratify=Tournament['result'], random_state=42)

Tournament.shape,train.shape,test.shape

# +
#train and validation split. split based of test length
train, val = train_test_split(train, test_size = len(test),
                              stratify=train['result'], random_state=42)

Tournament.shape,train.shape,test.shape,val.shape
# -

# ## random forest classifier

import category_encoders as ce
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import make_pipeline

# +
# assign features and target

target = "result"
features = train.columns.drop(["result","side"])

X_train = train[features]
y_train = train[target]
X_val = val[features]
y_val = val[target]
X_test = test[features]
y_test = test[target]
# -

features

train.select_dtypes(exclude='number').describe().T.sort_values(by='unique')

# +
# make the pipeline
rfc_pipeline = make_pipeline(
    ce.OrdinalEncoder(), 
    SimpleImputer(strategy='median'), 
    RandomForestClassifier(n_estimators=10, max_depth=3, min_samples_leaf=1, random_state=42)
)

# Fit on train, score on val
rfc_pipeline.fit(X_train, y_train)
print('Validation Accuracy', rfc_pipeline.score(X_val, y_val))
# -

# ### Random forest importance

import matplotlib.pyplot as plt


# +
rfc = rfc_pipeline.named_steps['randomforestclassifier']
importances = pd.Series(rfc.feature_importances_, X_train.columns)

n = 20
plt.figure(figsize=(10,n/2))
plt.title(f'Top {n} features')
importances.sort_values()[-n:].plot.barh(color='lightblue');
# -

# ## eli5 permuation

import eli5
from eli5.sklearn import PermutationImportance

# +
#eli doesnt work with pipline(workaround)
transformers = make_pipeline(
    ce.OrdinalEncoder(), 
    SimpleImputer(strategy='median')
)

X_train_transformed = transformers.fit_transform(X_train)
X_val_transformed = transformers.transform(X_val)

model = RandomForestClassifier(n_estimators=10, max_depth=3, min_samples_leaf=1, random_state=42)
model.fit(X_train_transformed, y_train)

# +
permuter = PermutationImportance(
    model, 
    scoring='accuracy', 
    n_iter=5, 
    random_state=42
)

permuter.fit(X_val_transformed, y_val)

# +
feature_names = X_val.columns.tolist()

eli5.show_weights(
    permuter,
    top=None, # show permutation importances for all features
    feature_names=feature_names
)
# -

# ## random forest updated after permutation (feat inportance) 

minimum_importance = 0
mask = permuter.feature_importances_ > minimum_importance
features = X_train.columns[mask]
X_train = X_train[features]

print('Shape after removing features:', X_train.shape)

# +
X_val = X_val[features]

pipeline = make_pipeline(
    ce.OrdinalEncoder(), 
    SimpleImputer(strategy='median'), 
    RandomForestClassifier(n_estimators=10, max_depth=3, min_samples_leaf=1, random_state=42)
)

# Fit on train, score on val
pipeline.fit(X_train, y_train)
print('Validation Accuracy', pipeline.score(X_val, y_val))
# -

from sklearn.metrics import accuracy_score
y_pred = pipeline.predict(X_val)
print('Validation Accuracy', accuracy_score(y_val, y_pred))

# ## xgboost model

from xgboost import XGBClassifier


encoder = ce.OrdinalEncoder()
X_train_encoded = encoder.fit_transform(X_train)
X_val_encoded = encoder.transform(X_val)


X_train_encoded = encoder.fit_transform(X_train)
X_val_encoded = encoder.transform(X_val)

eval_set = [(X_train_encoded, y_train), 
            (X_val_encoded, y_val)]

xgb_model = XGBClassifier(
    n_estimators=500, # <= 1000 trees, depends on early stopping
    max_depth=7,# try deeper trees because of high cardinality categoricals
    learning_rate=0.5, # try higher learning rate
    objective="multi:softmax",
    num_class=n+1,
    n_jobs=-1
)


xgb_model.fit(X_train_encoded, y_train,
          eval_set=eval_set, 
          eval_metric='merror',
          early_stopping_rounds=50
          )

results = xgb_model.evals_result()
train_error = results['validation_0']['merror']
val_error = results['validation_1']['merror']
epoch = range(1, len(train_error)+1)
plt.plot(epoch, train_error, label='Train')
plt.plot(epoch, val_error, label='Validation')
plt.ylabel('Classification Error')
plt.xlabel('Model Complexity (n_estimators)')
plt.ylim((0.18, 0.22)) # Zoom in
plt.legend();

# ## partitial dependency plot (pdpbox) specifically for categorial feature

from pdpbox.pdp import pdp_isolate, pdp_plot
from pdpbox import pdp
#isolate crunches the numbers
#plot is for grpahing

# Use Ordinal Encoder, outside of a pipeline
pdp_encoder = ce.OrdinalEncoder()
X_val_encoded_pdp = pdp_encoder.fit_transform(X_val)

pdp_model = RandomForestClassifier(n_estimators=10, max_depth=3, min_samples_leaf=1, random_state=42)
pdp_model.fit(X_val_encoded_pdp, y_val)

features

# +
#categorical setup
#need to use pre permutation features to make it work
# feature = the feature we want to change other features stay static

pdp_feature = "side"

pdp_dist = pdp.pdp_isolate(model=pdp_model, dataset=X_val_encoded_pdp, model_features=features, feature=pdp_feature)
pdp.pdp_plot(pdp_dist, pdp_feature);

# +
pdp_feature = 'teamkills'

isolated = pdp_isolate(
    model=pipeline, 
    dataset=X_val, 
    model_features=X_val.columns, 
    feature=pdp_feature
)
# -

pdp_plot(isolated, feature_name=pdp_feature);

# ## shap 

import shap

# +
# Get an individual observation to explain.
# For example, the 0th row from the test set.

row = X_val_encoded.iloc[[0]]
row
# -

# What was the answer
y_val.iloc[[0]]

# What does the model predict for this apartment?
xgb_model.predict(row)

processor = make_pipeline(
    ce.OrdinalEncoder(), 
    SimpleImputer(strategy='median')
)

X_train_processed = processor.fit_transform(X_train)
X_val_processed = processor.transform(X_val)

eval_set = [(X_train_processed, y_train), 
            (X_val_processed, y_val)]

model = XGBClassifier(n_estimators=1000, n_jobs=-1)
model.fit(X_train_processed, y_train, eval_set=eval_set, eval_metric='auc', 
          early_stopping_rounds=10)

from sklearn.metrics import roc_auc_score
X_test_processed = processor.transform(X_val)
class_index = 1
y_pred_proba = model.predict_proba(X_val_processed)[:, class_index]
print(f'Test ROC AUC for class {class_index}:')
print(roc_auc_score(y_val, y_pred_proba)) # Ranges from 0-1, higher is better

# Why did the model predict this?
explainer = shap.TreeExplainer(model)
row_processed = processor.transform(row)
shap_values = explainer.shap_values(row_processed)

shap.initjs()
shap.force_plot(
    base_value=explainer.expected_value, 
    shap_values=shap_values, 
    features=row, 
    link='logit' # For classification, this shows predicted probabilities
)



StarcoderdataJupyterScriptsDedupFiltered