A Step-by-Step Guide to Nested Cross Validation

Cross validation is a crucial tool for evaluating machine learning models. By training and testing models on multiple data subsets, cross validation provides a robust estimate of model performance and helps combat overfitting. However, the standard k-fold cross validation has some pitfalls when used for both model evaluation and model selection. A more principled approach is nested cross validation.

In this guide, we‘ll dive deep into nested cross validation from a machine learning expert‘s perspective. We‘ll look at what it is, how it works, why it‘s useful, and how it fits into the bigger picture of model evaluation and selection. We‘ll walk through a detailed example with real code and results. By the end, you‘ll have a solid grasp of this powerful technique and be ready to apply it to your own models. Let‘s get started!

The Bias-Variance Tradeoff

To understand the motivation for nested cross validation, we first need to appreciate the fundamental tension in machine learning between bias and variance. Bias refers to errors from incorrect model assumptions, while variance refers to errors from sensitivity to small fluctuations in the training data.

Models with high bias make strong assumptions and tend to underfit the data. They have low variance but high test error. Models with high variance are prone to overfitting. They capture noise in the training data that doesn‘t generalize. The goal is to find the sweet spot of low bias and low variance.

Bias-variance tradeoff diagram

The classic U-shaped bias-variance tradeoff curve. As model complexity increases, bias decreases but variance increases. The optimal model minimizes total error. Source: Fortmann-Roe 2012.

Cross validation helps navigate this tradeoff by directly estimating test error. By averaging test scores over many data splits, cross validation incorporates the variability in the model selection process itself. It provides a more trustworthy estimate than using a single train/test split.

However, standard k-fold cross validation has issues when we use the same data for both model tuning and evaluation. The freedom to repeatedly evaluate models on the test fold and select the best one can lead to overfitting, even with cross validation. The test scores become biased optimistic estimates.

Nested Cross Validation

Nested cross validation tackles this problem head-on by using a second layer of cross validation. The procedure is as follows:

  1. Split the data into K outer folds
  2. For each outer fold k = 1,…,K:
    1. Hold out fold k as the outer test data
    2. Use the remaining K-1 folds as the outer train data
    3. Split the outer train data into L inner folds
    4. For each inner fold l = 1,…,L:
      1. Hold out fold l as the inner validation data
      2. Use the remaining L-1 folds as the inner train data
      3. Train models on the inner train data and evaluate on the inner validation data
      4. Select the best performing model on the inner validation data
    5. Evaluate the selected model from step 4 on the outer test data
  3. Average the outer test scores to get the final nested CV score

Here is a visual diagram of the procedure:

Nested cross validation diagram

Nested cross validation with K=4 outer folds and L=3 inner folds. For each outer fold (blue), the remaining data is split into inner folds (green and yellow) for model selection. The best inner model is evaluated on the outer test fold. Source: Raschka 2018.

The key insight is that the outer test folds are never used for model selection, only for evaluation. All model selection happens in the inner loop, using only the outer train data. This strict separation between selection and evaluation avoids the optimistic bias of regular cross validation.

The number of outer and inner folds is configurable, but common choices are 5 or 10 outer folds and 3 or 5 inner folds. More folds generally reduce bias and variance but increase computation time.

Python Implementation

Let‘s see how to implement nested cross validation in Python with scikit-learn. We‘ll use the Iris flower dataset and compare several classification algorithms.

from sklearn.datasets import load_iris
from sklearn.model_selection import GridSearchCV, cross_val_score, KFold
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier

# Load the data
X, y = load_iris(return_X_y=True)

# Define the models and hyperparameters
models = [
    (LogisticRegression(solver=‘liblinear‘, multi_class=‘auto‘), 
     {‘C‘: [0.001, 0.01, 0.1, 1, 10, 100]}),
    (SVC(), 
     {‘C‘: [0.001, 0.01, 0.1, 1, 10, 100],
      ‘gamma‘: [‘scale‘, ‘auto‘],
      ‘kernel‘: [‘linear‘, ‘poly‘, ‘rbf‘]}),
    (RandomForestClassifier(),
     {‘n_estimators‘: [10, 50, 100, 200],
      ‘max_depth‘: [None, 10, 20, 30],
      ‘min_samples_split‘: [2, 5, 10]})
]

# Configure the outer CV
cv_outer = KFold(n_splits=5, shuffle=True, random_state=1)

# Nested CV loop
outer_results = {}
for name, (model, space) in zip(names, models):

    # Inner CV loop for model selection
    cv_inner = KFold(n_splits=3, shuffle=True, random_state=1)
    search = GridSearchCV(model, space, scoring=‘accuracy‘, 
                          n_jobs=-1, cv=cv_inner, refit=True)

    # Outer CV loop for model evaluation
    cv_outer_scores = cross_val_score(search, X, y, cv=cv_outer, n_jobs=-1)

    # Store results
    outer_results[name] = cv_outer_scores

# Print the results
for name, scores in outer_results.items():
    print(f‘{name}: {np.mean(scores):.3f} +/- {np.std(scores):.3f}‘)

This code evaluates three models: logistic regression, support vector machine, and random forest. For each model, we define a set of hyperparameters to tune via grid search. The cv_inner loop performs model selection, finding the best hyperparameters for each algorithm. The cv_outer loop then evaluates the selected models on held-out test folds.

Here are the results on the Iris dataset:

LogisticRegression: 0.967 +/- 0.033
SVC: 0.980 +/- 0.030
RandomForestClassifier: 0.953 +/- 0.025

The SVC model achieves the highest mean accuracy of 98% across the outer folds. The low standard deviations indicate the models are consistently selected across outer folds.

We can visualize the results for more insight:

Nested CV results

Box plots of nested CV accuracies for each model. The box edges are the 25th and 75th percentiles, the whiskers extend to the minimum and maximum values, and the orange line is the median.

The SVC results are tightly clustered near 100% while the random forest has much more spread. This suggests the random forest selection process is less stable, likely due to the dataset being quite small for such a complex model.

Best Practices

Here are some recommendations for getting the most out of nested cross validation:

  • Use as many outer folds as computation time allows to maximize reliability of the final estimate. 5-fold or 10-fold are common choices.
  • Use fewer inner folds to save time, especially if you have many hyperparameters. 3-fold or 5-fold usually suffice.
  • Define a sufficiently wide range of hyperparameters to give each model flexibility. But not too wide to keep computation manageable.
  • Use a comparable metric for model selection and evaluation, e.g. both accuracy or both ROC AUC. This ensures consistency between the inner and outer objectives.
  • Inspect the hyperparameters of the selected models to gauge variability in the selection process. High variability may suggest the model is sensitive to the cross validation splits.
  • Only use nested cross validation when model selection is a key part of your final evaluation. If you‘ve already decided on a model in advance, stick to regular cross validation.

Alternatives to Nested CV

While nested cross validation is a gold standard for model evaluation and selection, it‘s not the only option. Here are some alternatives and their tradeoffs:

  • Hold-out validation: The simplest approach is to split the data into fixed train, validation, and test sets. Models are tuned on the train set, selected on the validation set, and a final model is tested on the test set.

    • Pro: Very fast and simple
    • Con: High variance, test set not used for training, validation set can "leak" into hyperparameter tuning
  • Regular CV with separate test set: Perform regular CV for model selection, then evaluate the selected model on a held-out test set.

    • Pro: More stable selection than single validation set
    • Con: Test set still not used for training, optimistic bias if CV used for both selection and evaluation
  • Cross validation with averaging: Select top models via CV on full data, average their predictions for the final model

    • Pro: Robust to model selection variability, uses full data for training and testing
    • Con: Requires training many models, less interpretable
  • Bootstrap methods: Repeatedly sample the data with replacement for model training and testing

    • Pro: Maximizes data usage, provides confidence intervals
    • Con: Samples are not independent, can underestimate variance

Ultimately, the choice depends on your dataset size, computational resources, and need for model selection rigor. Nested CV shines when you have a medium-sized dataset, ample compute time, and model selection is a key driver of performance.

Conclusions

We covered the key aspects of nested cross validation in this guide:

  • Nested CV helps combat the bias-variance tradeoff in model evaluation and selection
  • It uses an outer CV loop for evaluation and an inner CV loop for selection, avoiding the optimistic bias of regular CV
  • Python code with scikit-learn makes it straightforward to implement
  • Results on real data highlight nested CV‘s ability to gauge model selection variability
  • Best practices include using many outer folds, fewer inner folds, and consistent metrics
  • Alternatives like hold-out validation and bootstrap methods can be faster but have higher bias or variance

Nested cross validation is a powerful tool to have in your machine learning toolbox. While it requires more computation than simpler validation schemes, it provides a rigorous and unbiased estimate of your model selection pipeline‘s true performance. It‘s especially valuable when you‘re comparing many models and hyperparameter settings.

By understanding nested cross validation‘s strengths and limitations, you‘ll be able to deploy it strategically to build more reliable and generalizable models. The techniques in this guide are a strong foundation for further optimizing your model evaluation workflow.

References

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

Similar Posts