Tuning Multiple Hyperparameters Grids#

This example uses the ‘fmri’ dataset, performs simple binary classification using a Support Vector Machine classifier while tuning multiple hyperparameters grids at the same time.

References#

Waskom, M.L., Frank, M.C., Wagner, A.D. (2016). Adaptive engagement of cognitive control in context-dependent decision-making. Cerebral Cortex.

# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
#
# License: AGPL
import numpy as np
from seaborn import load_dataset

from julearn import run_cross_validation
from julearn.utils import configure_logging
from julearn.pipeline import PipelineCreator

Set the logging level to info to see extra information

configure_logging(level="INFO")
2026-05-29 20:46:07,861 - julearn - INFO - ===== Lib Versions =====
2026-05-29 20:46:07,861 - julearn - INFO - numpy: 1.25.2
2026-05-29 20:46:07,861 - julearn - INFO - scipy: 1.16.3
2026-05-29 20:46:07,862 - julearn - INFO - sklearn: 1.3.0
2026-05-29 20:46:07,862 - julearn - INFO - pandas: 2.0.3
2026-05-29 20:46:07,862 - julearn - INFO - julearn: 0.3.1.dev0
2026-05-29 20:46:07,862 - julearn - INFO - ========================

Set the random seed to always have the same example

Load the dataset

df_fmri = load_dataset("fmri")
print(df_fmri.head())
  subject  timepoint event    region    signal
0     s13         18  stim  parietal -0.017552
1      s5         14  stim  parietal -0.080883
2     s12         18  stim  parietal -0.081033
3     s11         18  stim  parietal -0.046134
4     s10         18  stim  parietal -0.037970

Set the dataframe in the right format

df_fmri = df_fmri.pivot(
    index=["subject", "timepoint", "event"], columns="region", values="signal"
)

df_fmri = df_fmri.reset_index()
print(df_fmri.head())

X = ["frontal", "parietal"]
y = "event"
region subject  timepoint event   frontal  parietal
0           s0          0   cue  0.007766 -0.006899
1           s0          0  stim -0.021452 -0.039327
2           s0          1   cue  0.016440  0.000300
3           s0          1  stim -0.021054 -0.035735
4           s0          2   cue  0.024296  0.033220

Lets do a first attempt and use a linear SVM with the default parameters.

creator = PipelineCreator(problem_type="classification")
creator.add("zscore")
creator.add("svm", kernel="linear")

scores = run_cross_validation(X=X, y=y, data=df_fmri, model=creator)

print(scores["test_score"].mean())
2026-05-29 20:46:07,887 - julearn - INFO - Adding step zscore that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2026-05-29 20:46:07,887 - julearn - INFO - Step added
2026-05-29 20:46:07,887 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2026-05-29 20:46:07,887 - julearn - INFO - Setting hyperparameter kernel = linear
2026-05-29 20:46:07,887 - julearn - INFO - Step added
2026-05-29 20:46:07,888 - julearn - INFO - ==== Input Data ====
2026-05-29 20:46:07,888 - julearn - INFO - Using dataframe as input
2026-05-29 20:46:07,888 - julearn - INFO -      Features: ['frontal', 'parietal']
2026-05-29 20:46:07,888 - julearn - INFO -      Target: event
2026-05-29 20:46:07,888 - julearn - INFO -      Expanded features: ['frontal', 'parietal']
2026-05-29 20:46:07,888 - julearn - INFO -      X_types:{}
2026-05-29 20:46:07,888 - julearn - WARNING - The following columns are not defined in X_types: ['frontal', 'parietal']. They will be treated as continuous.
/private/var/folders/09/t22x2_p106j7p24khr0jdxrw0000gn/T/tmp4590_ea2/julearn/utils/logging.py:238: RuntimeWarning: The following columns are not defined in X_types: ['frontal', 'parietal']. They will be treated as continuous.
  warn(msg, category=category)
2026-05-29 20:46:07,890 - julearn - INFO - ====================
2026-05-29 20:46:07,890 - julearn - INFO -
2026-05-29 20:46:07,890 - julearn - INFO - = Model Parameters =
2026-05-29 20:46:07,891 - julearn - INFO - ====================
2026-05-29 20:46:07,891 - julearn - INFO -
2026-05-29 20:46:07,891 - julearn - INFO - = Data Information =
2026-05-29 20:46:07,891 - julearn - INFO -      Problem type: classification
2026-05-29 20:46:07,891 - julearn - INFO -      Number of samples: 532
2026-05-29 20:46:07,891 - julearn - INFO -      Number of features: 2
2026-05-29 20:46:07,891 - julearn - INFO - ====================
2026-05-29 20:46:07,891 - julearn - INFO -
2026-05-29 20:46:07,892 - julearn - INFO -      Number of classes: 2
2026-05-29 20:46:07,892 - julearn - INFO -      Target type: object
2026-05-29 20:46:07,893 - julearn - INFO -      Class distributions: event
cue     266
stim    266
Name: count, dtype: int64
2026-05-29 20:46:07,893 - julearn - INFO - Using outer CV scheme KFold(n_splits=5, random_state=None, shuffle=False)
2026-05-29 20:46:07,894 - julearn - INFO - Binary classification problem detected.
0.5939164168576971

Now lets tune a bit this SVM. We will use a grid search to tune the regularization parameter C and the kernel. We will also tune the gamma. But since the gamma is only used for the rbf kernel, we will use a different grid for the rbf kernel.

To specify two different sets of parameters for the same step, we can explicitly specify the name of the step. This is done by passing the name parameter to the add method.

creator = PipelineCreator(problem_type="classification")
creator.add("zscore")
creator.add("svm", kernel="linear", C=[0.01, 0.1], name="svm")
creator.add(
    "svm",
    kernel="rbf",
    C=[0.01, 0.1],
    gamma=["scale", "auto", 1e-2, 1e-3],
    name="svm",
)

search_params = {
    "kind": "grid",
    "cv": 2,  # to speed up the example
}

scores, estimator = run_cross_validation(
    X=X,
    y=y,
    data=df_fmri,
    model=creator,
    search_params=search_params,
    return_estimator="final",
)

print(scores["test_score"].mean())
2026-05-29 20:46:08,003 - julearn - INFO - Adding step zscore that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2026-05-29 20:46:08,004 - julearn - INFO - Step added
2026-05-29 20:46:08,004 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2026-05-29 20:46:08,004 - julearn - INFO - Setting hyperparameter kernel = linear
2026-05-29 20:46:08,004 - julearn - INFO - Tuning hyperparameter C = [0.01, 0.1]
2026-05-29 20:46:08,004 - julearn - INFO - Step added
2026-05-29 20:46:08,004 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2026-05-29 20:46:08,004 - julearn - INFO - Setting hyperparameter kernel = rbf
2026-05-29 20:46:08,004 - julearn - INFO - Tuning hyperparameter C = [0.01, 0.1]
2026-05-29 20:46:08,005 - julearn - INFO - Tuning hyperparameter gamma = ['scale', 'auto', 0.01, 0.001]
2026-05-29 20:46:08,005 - julearn - INFO - Step added
2026-05-29 20:46:08,005 - julearn - INFO - ==== Input Data ====
2026-05-29 20:46:08,005 - julearn - INFO - Using dataframe as input
2026-05-29 20:46:08,005 - julearn - INFO -      Features: ['frontal', 'parietal']
2026-05-29 20:46:08,005 - julearn - INFO -      Target: event
2026-05-29 20:46:08,005 - julearn - INFO -      Expanded features: ['frontal', 'parietal']
2026-05-29 20:46:08,006 - julearn - INFO -      X_types:{}
2026-05-29 20:46:08,006 - julearn - WARNING - The following columns are not defined in X_types: ['frontal', 'parietal']. They will be treated as continuous.
/private/var/folders/09/t22x2_p106j7p24khr0jdxrw0000gn/T/tmp4590_ea2/julearn/utils/logging.py:238: RuntimeWarning: The following columns are not defined in X_types: ['frontal', 'parietal']. They will be treated as continuous.
  warn(msg, category=category)
2026-05-29 20:46:08,007 - julearn - INFO - ====================
2026-05-29 20:46:08,007 - julearn - INFO -
2026-05-29 20:46:08,008 - julearn - INFO - = Model Parameters =
2026-05-29 20:46:08,008 - julearn - INFO - Tuning hyperparameters using grid
2026-05-29 20:46:08,008 - julearn - INFO - Hyperparameters:
2026-05-29 20:46:08,008 - julearn - INFO -      svm__C: [0.01, 0.1]
2026-05-29 20:46:08,009 - julearn - INFO - Using inner CV scheme KFold(n_splits=2, random_state=None, shuffle=False)
2026-05-29 20:46:08,009 - julearn - INFO - Search Parameters:
2026-05-29 20:46:08,009 - julearn - INFO -      cv: KFold(n_splits=2, random_state=None, shuffle=False)
2026-05-29 20:46:08,009 - julearn - INFO - ====================
2026-05-29 20:46:08,009 - julearn - INFO -
2026-05-29 20:46:08,010 - julearn - INFO - = Model Parameters =
2026-05-29 20:46:08,010 - julearn - INFO - Tuning hyperparameters using grid
2026-05-29 20:46:08,010 - julearn - INFO - Hyperparameters:
2026-05-29 20:46:08,010 - julearn - INFO -      svm__C: [0.01, 0.1]
2026-05-29 20:46:08,011 - julearn - INFO -      svm__gamma: ['scale', 'auto', 0.01, 0.001]
2026-05-29 20:46:08,011 - julearn - INFO - Using inner CV scheme KFold(n_splits=2, random_state=None, shuffle=False)
2026-05-29 20:46:08,011 - julearn - INFO - Search Parameters:
2026-05-29 20:46:08,011 - julearn - INFO -      cv: KFold(n_splits=2, random_state=None, shuffle=False)
2026-05-29 20:46:08,011 - julearn - INFO - ====================
2026-05-29 20:46:08,011 - julearn - INFO -
2026-05-29 20:46:08,012 - julearn - INFO - = Model Parameters =
2026-05-29 20:46:08,012 - julearn - INFO - Tuning hyperparameters using grid
2026-05-29 20:46:08,012 - julearn - INFO - Hyperparameters list:
2026-05-29 20:46:08,012 - julearn - INFO -      Set 0
2026-05-29 20:46:08,012 - julearn - INFO -              svm__C: [0.01, 0.1]
2026-05-29 20:46:08,012 - julearn - INFO -              set_column_types: [SetColumnTypes(X_types={})]
2026-05-29 20:46:08,013 - julearn - INFO -              svm: [SVC(kernel='linear')]
2026-05-29 20:46:08,013 - julearn - INFO -      Set 1
2026-05-29 20:46:08,013 - julearn - INFO -              svm__C: [0.01, 0.1]
2026-05-29 20:46:08,013 - julearn - INFO -              svm__gamma: ['scale', 'auto', 0.01, 0.001]
2026-05-29 20:46:08,013 - julearn - INFO -              set_column_types: [SetColumnTypes(X_types={})]
2026-05-29 20:46:08,014 - julearn - INFO -              svm: [SVC()]
2026-05-29 20:46:08,014 - julearn - INFO - Using inner CV scheme KFold(n_splits=2, random_state=None, shuffle=False)
2026-05-29 20:46:08,014 - julearn - INFO - Search Parameters:
2026-05-29 20:46:08,015 - julearn - INFO -      cv: KFold(n_splits=2, random_state=None, shuffle=False)
2026-05-29 20:46:08,015 - julearn - INFO - ====================
2026-05-29 20:46:08,015 - julearn - INFO -
2026-05-29 20:46:08,015 - julearn - INFO - = Data Information =
2026-05-29 20:46:08,015 - julearn - INFO -      Problem type: classification
2026-05-29 20:46:08,015 - julearn - INFO -      Number of samples: 532
2026-05-29 20:46:08,015 - julearn - INFO -      Number of features: 2
2026-05-29 20:46:08,015 - julearn - INFO - ====================
2026-05-29 20:46:08,016 - julearn - INFO -
2026-05-29 20:46:08,016 - julearn - INFO -      Number of classes: 2
2026-05-29 20:46:08,016 - julearn - INFO -      Target type: object
2026-05-29 20:46:08,017 - julearn - INFO -      Class distributions: event
cue     266
stim    266
Name: count, dtype: int64
2026-05-29 20:46:08,018 - julearn - INFO - Using outer CV scheme KFold(n_splits=5, random_state=None, shuffle=False)
2026-05-29 20:46:08,018 - julearn - INFO - Binary classification problem detected.
0.7087109857168048

It seems that we might have found a better model, but which one is it?

{'set_column_types': SetColumnTypes(X_types={}), 'svm': SVC(C=0.1), 'svm__C': 0.1, 'svm__gamma': 'scale'}
0.5

Total running time of the script: ( 0 minutes 2.702 seconds)

Gallery generated by Sphinx-Gallery