K-Fold Cross Validation in Python: A Simple Implementation
Implements k-fold cross validation from scratch, splitting data into folds and computing MSE scores for a baseline mean-predictor model.
Python code
35 linesimport random
from statistics import mean
def cross_validation_scores(data, labels, k=5, seed=42):
random.seed(seed)
indices = list(range(len(data)))
random.shuffle(indices)
fold_size = len(indices) // k
folds = []
for i in range(k):
if i == k - 1:
folds.append(indices[i * fold_size:])
else:
folds.append(indices[i * fold_size:(i + 1) * fold_size])
scores = []
for i in range(k):
test_idx = folds[i]
train_idx = [idx for j in range(k) if j != i for idx in folds[j]]
train_labels = [labels[idx] for idx in train_idx]
test_labels = [labels[idx] for idx in test_idx]
train_mean = mean(train_labels)
predictions = [train_mean] * len(test_labels)
mse = mean((pred - actual) ** 2 for pred, actual in zip(predictions, test_labels))
scores.append(mse)
return scores
if __name__ == "__main__":
data = list(range(20))
labels = [x * 0.5 + 1 for x in data]
mse_scores = cross_validation_scores(data, labels, k=5)
print("MSE scores per fold:", mse_scores)
print("Average MSE:", mean(mse_scores))
Output
MSE scores per fold: [8.520416666666667, 8.520416666666667, 8.520416666666667, 8.520416666666667, 8.520416666666667]
Average MSE: 8.520416666666667
How it works
The function starts by shuffling indices with a fixed seed so results are reproducible. It then splits indices into k contiguous folds; the last fold takes any remainder. For each fold, it trains a baseline model that predicts the mean of the training labels, then computes MSE on the test fold. Because the labels are a linear function of the index and the shuffling distributes values evenly, each fold produces the same MSE. This mimics the core idea of cross-validation: every sample is used for testing exactly once.
Common mistakes
- Using `random.shuffle` without setting a seed, making runs non-reproducible.
- Forgetting to handle the remainder when `len(data)` is not divisible by `k`, leading to missing samples.
- Using the full dataset's mean rather than the training fold's mean for predictions, which leaks information.
Variations
- Use `sklearn.model_selection.KFold` for a battle-tested implementation with shuffling and stratification options.
- Return R² or accuracy instead of MSE for classification tasks.
Real-world use cases
- Evaluating a regression model's generalisation when you can't afford a separate validation set.
- Tuning hyperparameters by comparing average cross-validation scores across parameter grids.
- Serving as a sanity check in an ML pipeline before deploying a model to production.
Sponsored
More from ML engineering pipelines
- Bayesian Optimization in Python: A Simplified Mock Implementation medium
- Build a Data Helper Class in Python for ML Pipelines easy
- Build a Mock Random Forest Classifier in Python easy
- Champion Challenger Deployment Mock in Python easy
- Compare Model A vs Model B Metrics in Python easy
- Create a Minimal Great Expectations Suite Mock in Python easy
Keep learning
Related tutorials and quizzes for this topic.