BANA409BANA409

Model Evaluation and Selection

  1. Build three decision tree models with different parameters
  2. Compare their performance using 10-fold cross validation (we also look at the train/test performance for each model to look for overfitting)
  3. Select the best model and use the corresponding parameters to train the final model using ALL training data
  4. Evaluate the final model on the test set and plot the confusion matrix
# import the packages
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('ggplot')

# read the titanic train dataset
df = pd.read_csv('titanic.csv')
df.info()

NOTE: In order to keep this demonstration code simple, we only choose three numerical features to train the model to avoid the tedious categorical feature encoding (one-hot encoding) - so the model performance won’t be good - focus on the workflow not the performance for this lecture. You should always use all important features in your real project.

# specify features and target
X = df[['SibSp', 'Parch', 'Fare']]
y = df['Survived']

Then, we split the data into a training set and a testing set. We choose to use 20% (test_size=0.2) of the data set as the test set. The dataset is randomized first and then splitted.

Fix the random_state ensures everyone running the code sees the same splitting result.

# Any number for the random_state is fine
# see 42: [https://en.wikipedia.org/wiki/42_(number)](https://en.wikipedia.org/wiki/42_(number))

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

Now, let’s initialize three decision tree models with different parameters:

from sklearn.tree import DecisionTreeClassifier

tree_clf1 = DecisionTreeClassifier(criterion='entropy')
tree_clf2 = DecisionTreeClassifier(criterion='entropy', max_depth=3)
tree_clf3 = DecisionTreeClassifier(criterion='gini', max_depth=6)

Next, we evaluate the performance of the three models using 5-fold cross validation (each model is trained and tested 5 times using different folds of the training data - 5 passes in total)

return_train_score=True also returns the training score for each pass, which is optional

from sklearn.model_selection import cross_validate

metrics = ['accuracy', 'precision', 'recall', 'f1']

tree_clf1_scores = cross_validate(tree_clf1, X_train, y_train, scoring=metrics, cv=5, return_train_score=True)
tree_clf2_scores = cross_validate(tree_clf2, X_train, y_train, scoring=metrics, cv=5, return_train_score=True)
tree_clf3_scores = cross_validate(tree_clf3, X_train, y_train, scoring=metrics, cv=5, return_train_score=True)

Print out tree_clf1_scores you should see the following, which is a dictionary:

Screen Shot 2022-04-11 at 7.34.13 PM.png

Let’s plot the training/testing accuracy for three models. We can see that model 1 clearly has overfitting problem, i.e., the training accuracy is significantly higher than the testing accuracy!!!

fig, ax = plt.subplots(1, 3, figsize=(20, 5))

ax[0].plot(tree_clf1_scores['train_accuracy'])
ax[0].plot(tree_clf1_scores['test_accuracy'])

ax[1].plot(tree_clf2_scores['train_accuracy'])
ax[1].plot(tree_clf2_scores['test_accuracy'])

ax[2].plot(tree_clf3_scores['train_accuracy'])
ax[2].plot(tree_clf3_scores['test_accuracy'])

1.png

We can also compare their average accuracy (or precision/recall/f1):

print('Tree 1 average accuracy score:', tree_clf1_scores['test_accuracy'].mean())
print('Tree 2 average accuracy score:', tree_clf2_scores['test_accuracy'].mean())
print('Tree 3 average accuracy score:', tree_clf3_scores['test_accuracy'].mean())

Screen Shot 2022-04-11 at 7.38.19 PM.png

In terms of accuracy, model 3 is the best. Let’s choose model 3 and use it’s parameter to train the final model using ALL training data (remember, we only used 80% of the training data in the 5-fold CV) and test it on the testing data (which has NEVER been used in training)

Pause here and think again about why we need to train model 3 using ALL training data

We can see that the test accuracy is slightly higher than the CV accuracy.

# we train the final model using ALL training data
tree_clf3.fit(X_train, y_train)

# get the prediction results from the testing set
y_pred = tree_clf3.predict(X_test)

# calculate accuracy, precision, recall, f1-score
# Note: y_test is the ground truth for the tesing set
# we have similiar score for the test set as the cross validation score - good
from sklearn.metrics import accuracy_score, recall_score, precision_score, f1_score

print(f'Accuracy Score : {accuracy_score(y_test, y_pred)}')
print(f'Precision Score : {precision_score(y_test, y_pred)}')
print(f'Recall Score : {recall_score(y_test, y_pred)}')
print(f'F1 Score : {f1_score(y_test, y_pred)}')

Screen Shot 2022-04-11 at 7.41.31 PM.png

We can also plot the confusion matrix based on the testing result:

plt.style.use('default') # use default style for confusion matrix plots

from sklearn.metrics import ConfusionMatrixDisplay
ConfusionMatrixDisplay.from_estimator(tree_clf3, X_test, y_test)

2.png

On this page