Walidacja krzyżowa i wyszukiwanie siatkowe pełnego pipeline'u
Uczą się Państwo przekazywać Pipeline do cross_val_score i GridSearchCV oraz używać notacji z podwójnym podkreśleniem do określania hiperparametrów poszczególnych kroków.
Walidacja krzyżowa i wyszukiwanie siatkowe pełnego pipeline'u to bezpłatna lekcja Machine Learning Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Machine Learning Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Machine Learning Academy zawiera 4 lekcji w sumie.
Części tej lekcji nie zostały jeszcze przetłumaczone i są wyświetlane po angielsku.
Why Grid-Search a Full Pipeline?
Hyperparameter tuning should always be combined with cross-validation to prevent overfitting the validation set. When your preprocessing steps have their own parameters (e.g., PCA's n_components, OneHotEncoder's drop), those must be tuned simultaneously with the model's parameters. Wrapping everything in a Pipeline and passing it to GridSearchCV ensures all of this is done correctly without leakage.
Passing a Pipeline to cross_val_score
The simplest way to evaluate a Pipeline fairly is cross_val_score(pipeline, X, y, cv=5). Each fold re-fits the entire pipeline — including scaler and classifier — on the training portion, then evaluates on the held-out fold. The mean and standard deviation of the returned array give you a reliable generalisation estimate.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_wine
import numpy as np
X, y = load_wine(return_X_y=True)
pipe = Pipeline([
('sc', StandardScaler()),
('lr', LogisticRegression(C=1.0, max_iter=300))
])
scores = cross_val_score(pipe, X, y, cv=5, scoring='accuracy')
print(f'CV accuracy: {np.mean(scores):.4f} +/- {np.std(scores):.4f}')Double-Underscore Notation for Pipeline Params
To reference a parameter of a named step inside the pipeline, use stepname__paramname. For nested structures like ColumnTransformer inside a Pipeline, chain the names: preprocessor__num__scaler__with_std. This convention is used both in set_params calls and in the param_grid dictionary passed to GridSearchCV.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])
# Print all tunable parameters
params = pipe.get_params()
for k, v in params.items():
print(f' {k}: {v}')Defining a param_grid for GridSearchCV
Create a dictionary where keys are pipeline parameter names (using double-underscore notation) and values are lists of candidates to try. GridSearchCV trains and evaluates the pipeline for every combination in the Cartesian product of all lists. The total number of fits equals len(combinations) * cv_folds.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_wine
X, y = load_wine(return_X_y=True)
pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])
param_grid = {
'svm__C': [0.1, 1.0, 10.0, 100.0],
'svm__kernel': ['rbf', 'linear'],
'svm__gamma': ['scale', 'auto']
}
grid = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1, scoring='accuracy')
grid.fit(X, y)
print('Best params:', grid.best_params_)
print('Best CV score:', grid.best_score_.round(4))Tuning Preprocessor Parameters Too
You can include preprocessor parameters in the same grid. For example, tune n_components of a PCA step alongside the classifier's regularisation. This finds the optimal compression level and model complexity simultaneously, which is more rigorous than tuning them in separate steps.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_digits
X, y = load_digits(return_X_y=True)
pipe = Pipeline([
('sc', StandardScaler()),
('pca', PCA()),
('lr', LogisticRegression(max_iter=500))
])
param_grid = {
'pca__n_components': [10, 20, 30, 40],
'lr__C': [0.1, 1.0, 10.0]
}
grid = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1)
grid.fit(X, y)
print('Best:', grid.best_params_)
print('Score:', grid.best_score_.round(4))Inspecting GridSearchCV Results
The cv_results_ attribute is a dictionary (convertible to a DataFrame) containing mean test scores, standard deviations, and fit times for every hyperparameter combination. Inspecting this DataFrame helps you understand the performance landscape and identify whether the best result is significantly better than the second-best, or if many parameter combinations perform similarly.
import pandas as pd
results = pd.DataFrame(grid.cv_results_)
results_sorted = results.sort_values('rank_test_score')
print(results_sorted[['param_pca__n_components', 'param_lr__C',
'mean_test_score', 'std_test_score']].head(6).to_string())RandomizedSearchCV for Large Parameter Spaces
When the parameter space is large, GridSearchCV becomes computationally prohibitive. RandomizedSearchCV samples a fixed number of combinations at random (controlled by n_iter), often finding near-optimal results in a fraction of the time. Use scipy.stats distributions for continuous parameters to sample from a range rather than discrete values.
from sklearn.model_selection import RandomizedSearchCV
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.datasets import load_wine
from scipy.stats import loguniform, uniform
X, y = load_wine(return_X_y=True)
pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])
param_dist = {
'svm__C': loguniform(0.01, 100),
'svm__gamma': loguniform(1e-4, 1),
'svm__kernel': ['rbf', 'linear']
}
rs = RandomizedSearchCV(pipe, param_dist, n_iter=30, cv=5, random_state=42, n_jobs=-1)
rs.fit(X, y)
print('Best params:', rs.best_params_)
print('Best score:', rs.best_score_.round(4))Nested CV: Evaluation and Selection Together
Standard grid search with cross-validation slightly overfits the validation set — after choosing the best hyperparameters, you have implicitly used the validation data. Nested cross-validation solves this: the outer loop evaluates the tuned model's generalisation, the inner loop selects hyperparameters. The outer loop score is an unbiased estimate of the final model's true test performance.
from sklearn.model_selection import GridSearchCV, cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.datasets import load_iris
import numpy as np
X, y = load_iris(return_X_y=True)
pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])
param_grid = {'svm__C': [0.1, 1.0, 10.0], 'svm__gamma': ['scale', 'auto']}
inner_cv = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1)
# Outer CV evaluates the tuning procedure itself
outer_scores = cross_val_score(inner_cv, X, y, cv=5)
print(f'Nested CV score: {np.mean(outer_scores):.4f} +/- {np.std(outer_scores):.4f}')Using the Best Estimator
After GridSearchCV.fit, the best_estimator_ attribute is the pipeline re-fitted on the entire training dataset using the best hyperparameters. This is the model you should use for final predictions. You can call predict, predict_proba, or score on it directly.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.datasets import load_wine
X, y = load_wine(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
pipe = Pipeline([('sc', StandardScaler()), ('svm', SVC())])
param_grid = {'svm__C': [0.1, 1.0, 10.0], 'svm__kernel': ['rbf', 'linear']}
grid = GridSearchCV(pipe, param_grid, cv=5, n_jobs=-1)
grid.fit(X_train, y_train)
best = grid.best_estimator_
print('Test accuracy:', best.score(X_test, y_test).round(4))Scoring Options in GridSearchCV
By default GridSearchCV uses the estimator's default score (accuracy for classifiers). You can specify any metric with the scoring parameter: 'roc_auc', 'f1', 'neg_mean_squared_error', or a custom scorer made with make_scorer. For imbalanced datasets, 'f1_macro' or 'roc_auc' are better choices than raw accuracy.
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
pipe = Pipeline([('sc', StandardScaler()), ('lr', LogisticRegression(max_iter=300))])
param_grid = {'lr__C': [0.01, 0.1, 1.0, 10.0]}
grid = GridSearchCV(pipe, param_grid, cv=5, scoring='roc_auc', n_jobs=-1)
grid.fit(X, y)
print('Best C:', grid.best_params_)
print('Best ROC-AUC:', grid.best_score_.round(4))Saving the Best Pipeline
After grid search, save the best pipeline to disk. This single file contains the scaler (with its fitted means and variances), the PCA (with its components), and the classifier (with its weights) — everything needed to reproduce predictions on new data. Load it in production and call predict directly.
import joblib
# Save the best estimator
joblib.dump(grid.best_estimator_, '/tmp/best_pipeline.pkl')
# Load and verify
loaded = joblib.load('/tmp/best_pipeline.pkl')
print('Loaded pipeline test score:', loaded.score(X_test, y_test).round(4))Quick Check
Test your understanding of cross-validating and grid-searching a full pipeline from this lesson.
Lesson Recap
In this lesson you learned: cross_val_score on a Pipeline re-fits all steps per fold and gives honest generalisation estimates, double-underscore notation references nested hyperparameters in param_grid, and RandomizedSearchCV efficiently explores large parameter spaces by sampling a fixed number of random combinations. Next up we save and load a full pipeline with joblib for production deployment.
Często zadawane pytania
Czy lekcja „Walidacja krzyżowa i wyszukiwanie siatkowe pełnego pipeline'u” jest bezpłatna?
Tak — pełny tekst „Walidacja krzyżowa i wyszukiwanie siatkowe pełnego pipeline'u” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Machine Learning Academy, przejdź na CoddyKit PRO. Kurs Machine Learning Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Walidacja krzyżowa i wyszukiwanie siatkowe pełnego pipeline'u”?
Uczą się Państwo przekazywać Pipeline do cross_val_score i GridSearchCV oraz używać notacji z podwójnym podkreśleniem do określania hiperparametrów poszczególnych kroków. Ćwiczysz Machine Learning Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Machine Learning Academy?
Nie wymagamy żadnego doświadczenia. Machine Learning Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Walidacja krzyżowa i wyszukiwanie siatkowe pełnego pipeline'u”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Machine Learning Academy?
Tak. Każda lekcja Machine Learning Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Tworzenie pierwszego pipeline'u: skalowanie i klasyfikator
- ColumnTransformer wewnątrz pipeline'u
- Walidacja krzyżowa i wyszukiwanie siatkowe pełnego pipeline'u
- Zapisywanie i wczytywanie pipeline'u za pomocą joblib