Avoiding Overfitting

The ultimate goal of machine learning is to make accurate predictions on unseen data. EvalML aims to help you build a model that will perform as you expect once it is deployed in to the real world.

One of the benefits of using EvalML to build models is that it provides guardrails to ensure you are building pipelines that will perform reliably in the future. This page describes the various ways EvalML helps you avoid overfitting to your data.

[1]:
import evalml

Detecting Label Leakage

A common problem is having features that include information from your label in your training data. By default, EvalML will provide a warning when it detects this may be the case.

Let’s set up a simple example to demonstrate what this looks like

[2]:
import pandas as pd

X = pd.DataFrame({
    "leaked_feature": [6, 6, 10, 5, 5, 11, 5, 10, 11, 4],
    "leaked_feature_2": [3, 2.5, 5, 2.5, 3, 5.5, 2, 5, 5.5, 2],
    "valid_feature": [3, 1, 3, 2, 4, 6, 1, 3, 3, 11]
})

y = pd.Series([1, 1, 0, 1, 1, 0, 1, 0, 0, 1])

automl = evalml.AutoClassificationSearch(
    max_pipelines=1,
    allowed_model_families=["linear_model"],
)

automl.search(X, y)
*****************************
* Beginning pipeline search *
*****************************

Optimizing for Precision. Greater score is better.

Searching up to 1 pipelines.
WARNING: Possible label leakage: leaked_feature, leaked_feature_2
✔ Logistic Regression Pipeline:            100%|██████████| Elapsed:00:01
✔ Optimization finished                    100%|██████████| Elapsed:00:01

In the example above, EvalML warned about the input features leaked_feature and leak_feature_2, which are both very closely correlated with the label we are trying to predict. If you’d like to turn this check off, set detect_label_leakage=False.

The second way to find features that may be leaking label information is to look at the top features of the model. As we can see below, the top features in our model are the 2 leaked features.

[3]:
best_pipeline = automl.best_pipeline
best_pipeline.feature_importances
[3]:
feature importance
0 leaked_feature -1.789393
1 leaked_feature_2 -1.645127
2 valid_feature -0.398465

Perform cross-validation for pipeline evaluation

By default, EvalML performs 3-fold cross validation when building pipelines. This means that it evaluates each pipeline 3 times using different sets of data for training and testing. In each trial, the data used for testing has no overlap from the data used for training.

While this is a good baseline approach, you can pass your own cross validation object to be used during modeling. The cross validation object can be any of the CV methods defined in scikit-learn or use a compatible API.

For example, if we wanted to do a time series split:

[4]:
from sklearn.model_selection import TimeSeriesSplit

X, y = evalml.demos.load_breast_cancer()

automl = evalml.AutoClassificationSearch(
    cv=TimeSeriesSplit(n_splits=6),
    max_pipelines=1
)

automl.search(X, y)
*****************************
* Beginning pipeline search *
*****************************

Optimizing for Precision. Greater score is better.

Searching up to 1 pipelines.
✔ Cat Boost Classification Pipeline:       100%|██████████| Elapsed:00:11
✔ Optimization finished                    100%|██████████| Elapsed:00:11

if we describe the 1 pipeline we built, we can see the scores for each of the 6 splits as determined by the cross-validation object we provided. We can also see the number of training examples per fold increased because we were using TimeSeriesSplit

[5]:
automl.describe_pipeline(0)
*************************************
* Cat Boost Classification Pipeline *
*************************************

Supported Problem Types: Binary Classification, Multiclass Classification
Model Family: CatBoost Classifier
Objective to Optimize: Precision (greater is better)
Number of features: 30

Pipeline Steps
==============
1. Simple Imputer
         * impute_strategy : most_frequent
         * fill_value : None
2. CatBoost Classifier
         * n_estimators : 369
         * eta : 0.4236547993389048
         * max_depth : 6

Training
========
Training for Binary Classification problems.
Total training time (including CV): 11.5 seconds

Cross Validation
----------------
             Precision    F1  Recall   AUC  Log Loss   MCC # Training # Testing
0                0.952 0.851   0.769 0.937     0.870 0.672     83.000    81.000
1                0.976 0.952   0.930 0.998     0.083 0.902    164.000    81.000
2                0.982 0.991   1.000 0.995     0.097 0.972    245.000    81.000
3                1.000 0.973   0.948 1.000     0.049 0.916    326.000    81.000
4                1.000 0.992   0.984 1.000     0.065 0.964    407.000    81.000
5                0.967 0.975   0.983 0.994     0.073 0.903    488.000    81.000
mean             0.980 0.956   0.936 0.987     0.206 0.888          -         -
std              0.019 0.053   0.086 0.025     0.326 0.110          -         -
coef of var      0.019 0.056   0.092 0.025     1.579 0.124          -         -

Detect unstable pipelines

When we perform cross validation we are trying generate an estimate of pipeline performance. EvalML does this by taking the mean of the score across the folds. If the performance across the folds varies greatly, it is indicative the the estimated value may be unreliable.

To protect the user against this, EvalML checks to see if the pipeline’s performance has a variance between the different folds. EvalML triggers a warning if the “coefficient of variance” of the scores (the standard deviation divided by mean) of the pipelines scores exeeds .2.

This warning will appear in the pipeline rankings under high_variance_cv.

[6]:
automl.rankings
[6]:
id pipeline_name score high_variance_cv parameters
0 0 Cat Boost Classification Pipeline 0.979504 False {'impute_strategy': 'most_frequent', 'n_estima...

Create holdout for model validation

EvalML offers a method to quickly create an holdout validation set. A holdout validation set is data that is not used during the process of optimizing or training the model. You should only use this validation set once you’ve picked the final model you’d like to use.

Below we create a holdout set of 20% of our data

[7]:
X, y = evalml.demos.load_breast_cancer()
X_train, X_holdout, y_train, y_holdout = evalml.preprocessing.split_data(X, y, test_size=.2)
[8]:
automl = evalml.AutoClassificationSearch(
    objective="recall",
    max_pipelines=3,
    detect_label_leakage=True
)
automl.search(X_train, y_train)
*****************************
* Beginning pipeline search *
*****************************

Optimizing for Recall. Greater score is better.

Searching up to 3 pipelines.
✔ Cat Boost Classification Pipeline:        33%|███▎      | Elapsed:00:07
✔ Logistic Regression Pipeline:             67%|██████▋   | Elapsed:00:07
✔ Logistic Regression Pipeline:            100%|██████████| Elapsed:00:07
✔ Optimization finished                    100%|██████████| Elapsed:00:07

then we can retrain the best pipeline on all of our training data and see how it performs compared to the estimate

[9]:
pipeline = automl.best_pipeline
pipeline.fit(X_train, y_train)
pipeline.score(X_holdout, y_holdout)
[9]:
(0.9722222222222222, {})