Skip to content

Commit 68b88a8

Browse files
Update learning curve examples to use LearningCurveSplitter API
Update all learning curve examples to use the new LearningCurveSplitter as cv_class for WithinSessionEvaluation: - examples/learning_curve/plot_learning_curve_p300.py - examples/learning_curve/plot_learning_curve_motor_imagery.py - examples/learning_curve/noplot_learning_curve_p300_external.py - examples/external/learning_curve_p300_external.py - examples/external/noplot_learning_curve_p300_external.py The new API uses cv_class=LearningCurveSplitter with cv_params containing: - data_size: dict with 'policy' and 'value' keys - n_perms: array of permutations per data size - test_size: fraction for test set This replaces the old data_size and n_perms parameters that were passed directly to WithinSessionEvaluation.
1 parent 7d38940 commit 68b88a8

File tree

5 files changed

+145
-60
lines changed

5 files changed

+145
-60
lines changed

examples/external/learning_curve_p300_external.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
- Time-Decoupled Linear Discriminant Analysis
1616
1717
We will use the P300 paradigm, which uses the AUC as metric.
18+
19+
The learning curve shows how model performance changes with different
20+
amounts of training data. We use LearningCurveSplitter which creates
21+
train/test splits where the test set is fixed for each permutation while
22+
the training set is subsampled to different sizes.
1823
"""
1924

2025
# Authors: Jan Sosulski
@@ -36,6 +41,7 @@
3641
import moabb
3742
from moabb.datasets import BNCI2014_009
3843
from moabb.evaluations import WithinSessionEvaluation
44+
from moabb.evaluations.splitters import LearningCurveSplitter
3945
from moabb.paradigms import P300
4046

4147

@@ -95,30 +101,39 @@
95101
# ----------
96102
#
97103
# We define the paradigm (P300) and use the BNCI 2014-009 dataset for it.
98-
# The evaluation will return a dataframe containing AUCs for each permutation
99-
# and dataset size.
104+
# The evaluation will return a DataFrame containing AUCs for each permutation
105+
# and data size.
106+
#
107+
# LearningCurveSplitter creates train/test splits where:
108+
# - The test set is fixed for each permutation (using StratifiedShuffleSplit)
109+
# - The training set is subsampled according to the data_size policy
110+
# - Multiple permutations are run for each data size
100111

101112
paradigm = P300(resample=processing_sampling_rate)
102113
dataset = BNCI2014_009()
103114
# Remove the slicing of the subject list to evaluate multiple subjects
104115
dataset.subject_list = dataset.subject_list[0:1]
105116
datasets = [dataset]
106117
overwrite = True # set to True if we want to overwrite cached results
107-
data_size = dict(policy="ratio", value=np.geomspace(0.02, 1, 6))
108-
# When the training data is sparse, perform more permutations than when we have
109-
# a lot of data
118+
119+
# Define learning curve parameters
120+
data_size = {"policy": "ratio", "value": np.geomspace(0.02, 1, 4)}
121+
# When the training data is sparse, perform more permutations than when we have a lot of data
110122
n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int)
111-
print(n_perms)
112-
# Guarantee reproducibility
113-
np.random.seed(7536298)
123+
114124
evaluation = WithinSessionEvaluation(
115125
paradigm=paradigm,
116126
datasets=datasets,
117-
data_size=data_size,
118-
n_perms=n_perms,
127+
cv_class=LearningCurveSplitter,
128+
cv_params={
129+
"data_size": data_size,
130+
"n_perms": n_perms,
131+
"test_size": 0.2,
132+
},
119133
suffix="examples_lr",
120134
overwrite=overwrite,
121135
return_epochs=True,
136+
random_state=7536298, # For reproducibility
122137
)
123138

124139
results = evaluation.process(pipelines)
@@ -127,7 +142,8 @@
127142
# Plot Results
128143
# ------------
129144
#
130-
# Here we plot the results.
145+
# Here we plot the results. The 'data_size' column contains the training set
146+
# size for each fold.
131147

132148
fig, ax = plt.subplots(facecolor="white", figsize=[8, 4])
133149

@@ -141,8 +157,8 @@
141157
sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1")
142158

143159
errbar_meaning = "subjects" if n_subs > 1 else "permutations"
144-
title_str = f"Errorbar shows Mean-CI across {errbar_meaning}"
145-
ax.set_xlabel("Amount of training samples")
160+
title_str = f"Learning Curve (errorbar: Mean-CI across {errbar_meaning})"
161+
ax.set_xlabel("Number of training samples")
146162
ax.set_ylabel("ROC AUC")
147163
ax.set_title(title_str)
148164
fig.tight_layout()

examples/external/noplot_learning_curve_p300_external.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
- Time-Decoupled Linear Discriminant Analysis
1616
1717
We will use the P300 paradigm, which uses the AUC as metric.
18+
19+
The learning curve shows how model performance changes with different
20+
amounts of training data. We use LearningCurveSplitter which creates
21+
train/test splits where the test set is fixed for each permutation while
22+
the training set is subsampled to different sizes.
1823
"""
1924

2025
# Authors: Jan Sosulski
@@ -36,6 +41,7 @@
3641
import moabb
3742
from moabb.datasets import BNCI2014_009
3843
from moabb.evaluations import WithinSessionEvaluation
44+
from moabb.evaluations.splitters import LearningCurveSplitter
3945
from moabb.paradigms import P300
4046

4147

@@ -96,29 +102,38 @@
96102
# ----------
97103
#
98104
# We define the paradigm (P300) and use the BNCI 2014-009 dataset for it.
99-
# The evaluation will return a dataframe containing AUCs for each permutation
100-
# and dataset size.
105+
# The evaluation will return a DataFrame containing AUCs for each permutation
106+
# and data size.
107+
#
108+
# LearningCurveSplitter creates train/test splits where:
109+
# - The test set is fixed for each permutation (using StratifiedShuffleSplit)
110+
# - The training set is subsampled according to the data_size policy
111+
# - Multiple permutations are run for each data size
101112

102113
paradigm = P300(resample=processing_sampling_rate)
103114
dataset = BNCI2014_009()
104115
# Remove the slicing of the subject list to evaluate multiple subjects
105116
dataset.subject_list = dataset.subject_list[0:1]
106117
datasets = [dataset]
107118
overwrite = True # set to True if we want to overwrite cached results
108-
data_size = dict(policy="ratio", value=np.geomspace(0.02, 1, 6))
109-
# When the training data is sparse, perform more permutations than when we have
110-
# a lot of data
119+
120+
# Define learning curve parameters
121+
data_size = {"policy": "ratio", "value": np.geomspace(0.02, 1, 4)}
122+
# When the training data is sparse, perform more permutations than when we have a lot of data
111123
n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int)
112-
print(n_perms)
113-
# Guarantee reproducibility
114-
np.random.seed(7536298)
124+
115125
evaluation = WithinSessionEvaluation(
116126
paradigm=paradigm,
117127
datasets=datasets,
118-
data_size=data_size,
119-
n_perms=n_perms,
128+
cv_class=LearningCurveSplitter,
129+
cv_params={
130+
"data_size": data_size,
131+
"n_perms": n_perms,
132+
"test_size": 0.2,
133+
},
120134
suffix="examples_lr",
121135
overwrite=overwrite,
136+
random_state=7536298, # For reproducibility
122137
)
123138

124139
results = evaluation.process(pipelines)
@@ -127,7 +142,8 @@
127142
# Plot Results
128143
# ------------
129144
#
130-
# Here we plot the results.
145+
# Here we plot the results. The 'data_size' column contains the training set
146+
# size for each fold.
131147

132148
fig, ax = plt.subplots(facecolor="white", figsize=[8, 4])
133149

@@ -141,8 +157,8 @@
141157
sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1")
142158

143159
errbar_meaning = "subjects" if n_subs > 1 else "permutations"
144-
title_str = f"Errorbar shows Mean-CI across {errbar_meaning}"
145-
ax.set_xlabel("Amount of training samples")
160+
title_str = f"Learning Curve (errorbar: Mean-CI across {errbar_meaning})"
161+
ax.set_xlabel("Number of training samples")
146162
ax.set_ylabel("ROC AUC")
147163
ax.set_title(title_str)
148164
fig.tight_layout()

examples/learning_curve/noplot_learning_curve_p300_external.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
- Time-Decoupled Linear Discriminant Analysis
1616
1717
We will use the P300 paradigm, which uses the AUC as metric.
18+
19+
The learning curve shows how model performance changes with different
20+
amounts of training data. We use LearningCurveSplitter which creates
21+
train/test splits where the test set is fixed for each permutation while
22+
the training set is subsampled to different sizes.
1823
"""
1924

2025
# Authors: Jan Sosulski
@@ -36,6 +41,7 @@
3641
import moabb
3742
from moabb.datasets import BNCI2014_009
3843
from moabb.evaluations import WithinSessionEvaluation
44+
from moabb.evaluations.splitters import LearningCurveSplitter
3945
from moabb.paradigms import P300
4046

4147

@@ -96,29 +102,38 @@
96102
# ----------
97103
#
98104
# We define the paradigm (P300) and use the BNCI 2014-009 dataset for it.
99-
# The evaluation will return a dataframe containing AUCs for each permutation
100-
# and dataset size.
105+
# The evaluation will return a DataFrame containing AUCs for each permutation
106+
# and data size.
107+
#
108+
# LearningCurveSplitter creates train/test splits where:
109+
# - The test set is fixed for each permutation (using StratifiedShuffleSplit)
110+
# - The training set is subsampled according to the data_size policy
111+
# - Multiple permutations are run for each data size
101112

102113
paradigm = P300(resample=processing_sampling_rate)
103114
dataset = BNCI2014_009()
104115
# Remove the slicing of the subject list to evaluate multiple subjects
105116
dataset.subject_list = dataset.subject_list[0:1]
106117
datasets = [dataset]
107118
overwrite = True # set to True if we want to overwrite cached results
108-
data_size = dict(policy="ratio", value=np.geomspace(0.02, 1, 6))
109-
# When the training data is sparse, perform more permutations than when we have
110-
# a lot of data
119+
120+
# Define learning curve parameters
121+
data_size = {"policy": "ratio", "value": np.geomspace(0.02, 1, 4)}
122+
# When the training data is sparse, perform more permutations than when we have a lot of data
111123
n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int)
112-
print(n_perms)
113-
# Guarantee reproducibility
114-
np.random.seed(7536298)
124+
115125
evaluation = WithinSessionEvaluation(
116126
paradigm=paradigm,
117127
datasets=datasets,
118-
data_size=data_size,
119-
n_perms=n_perms,
128+
cv_class=LearningCurveSplitter,
129+
cv_params={
130+
"data_size": data_size,
131+
"n_perms": n_perms,
132+
"test_size": 0.2,
133+
},
120134
suffix="examples_lr",
121135
overwrite=overwrite,
136+
random_state=7536298, # For reproducibility
122137
)
123138

124139
results = evaluation.process(pipelines)
@@ -127,7 +142,8 @@
127142
# Plot Results
128143
# ------------
129144
#
130-
# Here we plot the results.
145+
# Here we plot the results. The 'data_size' column contains the training set
146+
# size for each fold.
131147

132148
fig, ax = plt.subplots(facecolor="white", figsize=[8, 4])
133149

@@ -141,8 +157,8 @@
141157
sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1")
142158

143159
errbar_meaning = "subjects" if n_subs > 1 else "permutations"
144-
title_str = f"Errorbar shows Mean-CI across {errbar_meaning}"
145-
ax.set_xlabel("Amount of training samples")
160+
title_str = f"Learning Curve (errorbar: Mean-CI across {errbar_meaning})"
161+
ax.set_xlabel("Number of training samples")
146162
ax.set_ylabel("ROC AUC")
147163
ax.set_title(title_str)
148164
fig.tight_layout()

examples/learning_curve/plot_learning_curve_motor_imagery.py

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
================================================
55
66
This example shows how to perform a within session motor imagery analysis on the
7-
very popular dataset 2a from the BCI competition IV.
7+
very popular dataset 2a from the BCI competition IV while creating learning curves.
88
99
We will compare two pipelines :
1010
@@ -13,6 +13,11 @@
1313
1414
We will use the LeftRightImagery paradigm. This will restrict the analysis
1515
to two classes (left- vs right-hand) and use AUC as metric.
16+
17+
The learning curve shows how model performance changes with different
18+
amounts of training data. We use LearningCurveSplitter which creates
19+
train/test splits where the test set is fixed for each permutation while
20+
the training set is subsampled to different sizes.
1621
"""
1722

1823
# Original author: Alexandre Barachant <alexandre.barachant@gmail.com>
@@ -33,6 +38,7 @@
3338
import moabb
3439
from moabb.datasets import BNCI2014_001
3540
from moabb.evaluations import WithinSessionEvaluation
41+
from moabb.evaluations.splitters import LearningCurveSplitter
3642
from moabb.paradigms import LeftRightImagery
3743

3844

@@ -65,8 +71,13 @@
6571
# ----------
6672
#
6773
# We define the paradigm (LeftRightImagery) and the dataset (BNCI2014_001).
68-
# The evaluation will return a DataFrame containing a single AUC score for
69-
# each subject / session of the dataset, and for each pipeline.
74+
# The evaluation will return a DataFrame containing AUCs for each permutation
75+
# and data size.
76+
#
77+
# LearningCurveSplitter creates train/test splits where:
78+
# - The test set is fixed for each permutation (using StratifiedShuffleSplit)
79+
# - The training set is subsampled according to the data_size policy
80+
# - Multiple permutations are run for each data size
7081
#
7182
# Results are saved into the database, so that if you add a new pipeline, it
7283
# will not run again the evaluation unless a parameter has changed. Results can
@@ -77,17 +88,24 @@
7788
dataset.subject_list = dataset.subject_list[:1]
7889
datasets = [dataset]
7990
overwrite = True # set to True if we want to overwrite cached results
80-
# Evaluate for a specific number of training samples per class
81-
data_size = dict(policy="per_class", value=np.array([5, 10, 30, 50]))
91+
92+
# Define learning curve parameters
93+
data_size = {"policy": "ratio", "value": np.geomspace(0.1, 1, 5)}
8294
# When the training data is sparse, perform more permutations than when we have a lot of data
83-
n_perms = np.floor(np.geomspace(20, 2, len(data_size["value"]))).astype(int)
95+
n_perms = np.floor(np.geomspace(10, 2, len(data_size["value"]))).astype(int)
96+
8497
evaluation = WithinSessionEvaluation(
8598
paradigm=paradigm,
8699
datasets=datasets,
100+
cv_class=LearningCurveSplitter,
101+
cv_params={
102+
"data_size": data_size,
103+
"n_perms": n_perms,
104+
"test_size": 0.2,
105+
},
87106
suffix="examples",
88107
overwrite=overwrite,
89-
data_size=data_size,
90-
n_perms=n_perms,
108+
random_state=42, # For reproducibility
91109
)
92110

93111
results = evaluation.process(pipelines)
@@ -99,7 +117,8 @@
99117
# ------------
100118
#
101119
# We plot the accuracy as a function of the number of training samples, for
102-
# each pipeline
120+
# each pipeline. The 'data_size' column contains the training set size for
121+
# each fold.
103122

104123
fig, ax = plt.subplots(facecolor="white", figsize=[8, 4])
105124

@@ -113,8 +132,8 @@
113132
sns.pointplot(data=r, x="data_size", y="score", hue="pipeline", ax=ax, palette="Set1")
114133

115134
errbar_meaning = "subjects" if n_subs > 1 else "permutations"
116-
title_str = f"Errorbar shows Mean-CI across {errbar_meaning}"
117-
ax.set_xlabel("Amount of training samples")
135+
title_str = f"Learning Curve (errorbar: Mean-CI across {errbar_meaning})"
136+
ax.set_xlabel("Number of training samples")
118137
ax.set_ylabel("ROC AUC")
119138
ax.set_title(title_str)
120139
fig.tight_layout()

0 commit comments

Comments
 (0)