How many columns to keep is a setting, just like C. So you can search both at once, with cross-validation on the training rows, and open the test rows once at the end.
Task: write tune_k_and_c(k_values, c_values).
load_breast_cancer(return_X_y=True, as_frame=True).train_test_split(X, y, test_size=0.25, random_state=0, stratify=y).Pipeline([("scale", StandardScaler()), ("select", SelectKBest(f_classif)), ("model", SVC())]).GridSearchCV on it with cv=5, searching every combination of k_values for the selector's k and c_values for the model's C. Fit it on the training rows.Return a dict:
"best": the search's best_params_, exactly as scikit-learn gives it,"cv": the best cross-validated score, rounded to 3 decimal places,"test": the winner's accuracy on the test rows, rounded to 3 decimal places.