A single train/test split gives one performance estimate that depends partly on luck — which specific rows happened to land in the test set — cross-validation produces a more reliable estimate by repeating the process multiple times.
from sklearn.model_selection import cross_val_score, KFold
model = LogisticRegression()
scores = cross_val_score(model, X, y, cv=5, scoring="accuracy") # 5-fold cross-validation
print(scores) # 5 individual accuracy scores, one per fold
print(scores.mean(), scores.std()) # average performance and its variability
kf = KFold(n_splits=5, shuffle=True, random_state=42) # explicit control over the folds
scores = cross_val_score(model, X, y, cv=kf)
K-fold cross-validation splits the full dataset into k equal-sized "folds," then trains and evaluates the model k times, each time holding out a different fold as the test set and training on the remaining k-1 folds — every data point ends up in the test set exactly once across all k runs. The result is k separate performance scores rather than one, whose mean gives a more stable estimate of true performance and whose standard deviation reveals how much that performance varies depending on which specific data happened to be held out.
A single train/test split's score can be noisy, especially on smaller datasets, potentially painting an unrealistically rosy or pessimistic picture purely by chance of the split — cross-validation's average across multiple folds smooths out that luck factor, making it the standard, more trustworthy approach for comparing models or reporting expected real-world performance, and the technique used throughout the hyperparameter tuning covered later in this notebook.