Filter bank CSP with Riemannian weighting for disability-centric motor imagery brain computer interface.
The 1 match
- [1] § Materials and methods › Multi-classification ↔ BCI_R-FBCSP.ipynb, lines 1066 to 1125 · score 0.51 · Random Forest Classifier, Linear Discriminant, Layer, MLP, LDA · Report a mismatch
Paper
Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 1,259 lines · 47 KB · CC-BY-4.0 · 1 match
- # %%
- from scipy import signal
- from scipy.signal import firwin, lfilter
- import mne
- import numpy as np
- from sklearn.metrics import classification_report, accuracy_score
- from sklearn.preprocessing import StandardScaler
- from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
- from scipy.signal import butter, sosfiltfilt, filtfilt
- from sklearn.metrics import accuracy_score, cohen_kappa_score, precision_score, recall_score
- from mne.decoding import CSP
- from scipy.signal import welch
- from sklearn.preprocessing import StandardScaler
- import logging
- import scipy.io as io
- import os
- # %%
- class IV2aGdfReader:
- stimcodes = ('769', '770', '771', '772')
- channels_to_remove = ['EOG-left', 'EOG-central', 'EOG-right']
- def __init__(self, data_dir: str=None):
- self.data_dir = data_dir
- if data_dir is not None:
- self.filenames = [name for name in os.listdir(
- self.data_dir) if name.endswith(".gdf")]
- else:
- self.filenames = []
- def load_raw_data_gdf(self, filename: str):
- if self.data_dir is not None:
- filepath = os.path.join(self.data_dir, filename)
- else:
- filepath = filename
- logging.info(f"Read {filepath}")
- return mne.io.read_raw_gdf(filepath, verbose="ERROR")
- def read_file(self, filename: str, tmin=0.5, tmax=3.0, baseline=None, matfile=None): #tmin=0.5, tmax=2.5
- gdf_name = os.path.basename(filename).split(".")[0]
- subject = gdf_name[1:3]
- raw_data = self.load_raw_data_gdf(filename)
- sample_freq = raw_data.info.get('sfreq')
- events, event_ids = mne.events_from_annotations(raw_data)
- if "T" == gdf_name[-1]:
- stims = [value for key, value in event_ids.items()
- if key in self.stimcodes]
- elif "E" == gdf_name[-1]:
- stims = [value for key, value in event_ids.items() if key == "783"]
- else:
- all_stimcodes = self.stimcodes + ["783"]
- stims = [value for key, value in event_ids.items() if key in all_stimcodes]
- epochs = mne.Epochs(raw_data, events, event_id=stims, tmin=tmin, tmax=tmax,
- baseline=baseline, preload=True, proj=False)
- epochs = epochs.drop_channels(self.channels_to_remove)
- # Récupérer les noms et indices des canaux EEG restants
- ch_names = epochs.ch_names # Liste des noms de canaux
- ch_indices = {name: idx for idx, name in enumerate(ch_names)}
- if matfile is not None:
- mat = io.loadmat(matfile)
- y_labels = mat["classlabel"].reshape(-1) - 1
- elif self.data_dir is not None:
- mat = io.loadmat(os.path.join(
- self.data_dir, "true_labels", f"{gdf_name}.mat"))
- y_labels = mat["classlabel"].reshape(-1) - 1
- else:
- y_labels = None
- x_data = epochs.get_data()#*1e6
- eeg_data = {'x_data': x_data,
- 'y_labels': y_labels,
- 'fs': sample_freq,
- 'ch_names':ch_names,
- 'ch_indices':ch_indices,
- "subject": subject}
- return eeg_data
- # %%
- base_path ="C:/Users/Client/Desktop/Jihen_BCI/BCI_IV_DSIIa"
- reader = IV2aGdfReader(data_dir=base_path)
- # %%
- %%capture
- # Liste des fichiers à traiter
- file_extensions = ['T', 'E']
- base_filename = "A{:02d}{}.gdf"
- # Initialiser les listes pour stocker toutes les données et étiquettes .T et .E
- all_x_data_T = []
- all_x_data_E = []
- all_y_labels_T = []
- all_y_labels_E = []
- all_ch_namesT = []
- all_ch_indicesT = []
- all_ch_namesE = []
- all_ch_indicesE = []
- # Boucle sur les extensions de fichiers
- for ext in file_extensions:
- # Boucle sur les fichiers (9 fichiers au total)
- for i in range(1, 10):
- filename = os.path.join(base_path, base_filename.format(i, ext))
- data = reader.read_file(filename)
- # Accéder aux données et aux étiquettes
- x_data = data['x_data']
- y_labels = data['y_labels']
- ch_names = data['ch_names']
- ch_indices = data['ch_indices']
- # Ajouter les données et étiquettes aux listes correspondantes
- if ext == 'T':
- all_x_data_T.append(x_data)
- all_y_labels_T.append(y_labels)
- all_ch_namesT .append(ch_names)
- all_ch_indicesT .append(ch_indices)
- elif ext == 'E':
- all_x_data_E.append(x_data)
- all_y_labels_E.append(y_labels)
- all_ch_namesE .append(ch_names)
- all_ch_indicesE .append(ch_indices)
- # Imprimer la taille des données et des étiquettes pour chaque fichier
- print(f"Taille des données ({filename}):", x_data.shape)
- print(f"Taille des étiquettes ({filename}):", y_labels.shape)
- # Convertir les listes en tableaux numpy
- all_x_data_T = np.array(all_x_data_T)
- all_y_labels_T = np.array(all_y_labels_T)
- all_x_data_E = np.array(all_x_data_E)
- all_y_labels_E = np.array(all_y_labels_E)
- # %%
- # Imprimer la taille totale des données et des étiquettes pour chaque catégorie
- print("Taille totale des données .T (all_x_data_T):", all_x_data_T.shape)
- print("Taille totale des étiquettes .T (all_y_labels_T):", all_y_labels_T.shape)
- print("Taille totale des données .E (all_x_data_E):", all_x_data_E.shape)
- print("Taille totale des étiquettes .E (all_y_labels_E):", all_y_labels_E.shape)
- # %%
- def my_filter_function( data, lowcut, highcut, fs, order):
- nyquist = 0.5 * fs
- low = lowcut / nyquist
- high = highcut / nyquist
- sos = butter(order, [low, high], btype='band', output='sos')
- # Increase the padlen parameter to increase the filter window size
- filtered_data = sosfiltfilt(sos, data, axis=-1, padlen=250)
- return filtered_data
- # %% [markdown]
- # # fonction R-FBCSP
- # %%
- import numpy as np
- from pyriemann.utils.mean import mean_riemann
- from scipy.linalg import eigh
- def CSP_OVR_optim(epochs, labels, n_components=3):
- n_trials, n_channels, _ = epochs.shape
- classes = np.unique(labels)
- all_features = []
- all_W = []
- # 1. Calcul des matrices de covariance normalisées
- covmats = []
- for epoch in epochs:
- cov = epoch @ epoch.T
- trace = np.trace(cov)
- cov_norm = cov / (trace + 1e-10)
- covmats.append(cov_norm)
- covmats = np.array(covmats)
- for c in classes:
- y_binary = (labels == c).astype(int)
- # 2. Moyennes riemanniennes
- cov_A = mean_riemann(covmats[y_binary == 1])
- cov_B = mean_riemann(covmats[y_binary == 0])
- # 3. Blanchiment robuste
- cov_sum = cov_A + cov_B
- eigvals, eigvecs = eigh(cov_sum)
- eigvals = np.clip(eigvals, 1e-6, None)
- P = eigvecs @ np.diag(1.0 / np.sqrt(eigvals)) @ eigvecs.T
- # 4. Diagonalisation
- S_A = P @ cov_A @ P.T
- eigvals_s, eigvecs_s = eigh(S_A)
- # 5. Tri des vecteurs
- idx = np.argsort(eigvals_s)[::-1]
- W = eigvecs_s[:, idx].T @ P
- W_c = np.vstack([W[:n_components], W[-n_components:]])
- all_W.append(W_c)
- # 6. Extraction des log-variances
- features = []
- for epoch in epochs:
- Z = W_c @ epoch
- var = np.var(Z, axis=1)
- var_sum = np.sum(var)
- log_var = np.log((var + 1e-10) / (var_sum + 1e-10))
- features.append(log_var)
- all_features.append(np.array(features))
- # 7. Concatenation des features de tous les classifieurs OVR
- final_features = np.concatenate(all_features, axis=1)
- return final_features, all_W
- # %% [markdown]
- # # Global filtering
- # %%
- order_filter = 6
- lowcut = 8.0
- highcut = 30.0
- fs = 250
- n_components_csp = 22
- # Train
- all_person_featuresT = []
- for person_index, (x_data_T, y_labels_T) in enumerate(zip(all_x_data_T, all_y_labels_T)):
- filtered_dataT = my_filter_function(x_data_T, lowcut, highcut, fs, order=order_filter)
- features_T, _ = CSP_OVR_optim(filtered_dataT, y_labels_T, n_components=n_components_csp)
- all_person_featuresT.append(features_T)
- # Test
- all_person_featuresE = []
- for person_index, (x_data_E, y_labels_E) in enumerate(zip(all_x_data_E, all_y_labels_E)):
- filtered_dataE = my_filter_function(x_data_E, lowcut, highcut, fs, order=order_filter)
- features_E, _ = CSP_OVR_optim(filtered_dataE, y_labels_E, n_components=n_components_csp)
- all_person_featuresE.append(features_E)
- # Convertir en numpy arrays
- all_person_featuresT = np.array(all_person_featuresT)
- all_person_featuresE = np.array(all_person_featuresE)
- # %%
- print(np.shape(all_person_featuresT))
- print(np.shape(all_person_featuresE))
- # %% [markdown]
- # # LDA Classification
- # %%
- from sklearn.model_selection import KFold
- from sklearn.preprocessing import StandardScaler
- from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
- from sklearn.pipeline import make_pipeline
- import numpy as np
- # Initialisation des listes
- cv_train_accuracies, cv_val_accuracies, cv_test_accuracies = [], [], []
- cv_train_precisions, cv_val_precisions, cv_test_precisions = [], [], []
- cv_train_recalls, cv_val_recalls, cv_test_recalls = [], [], []
- cv_train_f1s, cv_val_f1s, cv_test_f1s = [], [], []
- kfold = KFold(n_splits=5, shuffle=True, random_state=42)
- for i, (features_train, y_labels_T, features_test, y_labels_E) in enumerate(zip(all_person_featuresT, all_y_labels_T,
- all_person_featuresE, all_y_labels_E)):
- print(f"\nProcessing subject {i + 1}")
- # Pour accumuler les scores par pli
- fold_train_accs, fold_val_accs = [], []
- fold_train_prec, fold_val_prec = [], []
- fold_train_rec, fold_val_rec = [], []
- fold_train_f1, fold_val_f1 = [], []
- model = make_pipeline(StandardScaler(),
- LinearDiscriminantAnalysis(solver='lsqr', shrinkage='auto',
- n_components=3, tol=1e-4))
- # Validation croisée
- for train_idx, val_idx in kfold.split(features_train):
- X_train_fold, X_val_fold = features_train[train_idx], features_train[val_idx]
- y_train_fold, y_val_fold = y_labels_T[train_idx], y_labels_T[val_idx]
- model.fit(X_train_fold, y_train_fold)
- # Prédictions
- y_train_pred = model.predict(X_train_fold)
- y_val_pred = model.predict(X_val_fold)
- # Accuracy
- fold_train_accs.append(accuracy_score(y_train_fold, y_train_pred))
- fold_val_accs.append(accuracy_score(y_val_fold, y_val_pred))
- # Precision, Recall, F1
- fold_train_prec.append(precision_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_prec.append(precision_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_rec.append(recall_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_rec.append(recall_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_f1.append(f1_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_f1.append(f1_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- # Réentraînement sur tout l'ensemble d'apprentissage
- model.fit(features_train, y_labels_T)
- y_test_pred = model.predict(features_test)
- # Test scores
- test_acc = accuracy_score(y_labels_E, y_test_pred)
- test_prec = precision_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_rec = recall_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_f1 = f1_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- # Moyennes sur les plis
- cv_train_accuracies.append(np.mean(fold_train_accs))
- cv_val_accuracies.append(np.mean(fold_val_accs))
- cv_test_accuracies.append(test_acc)
- cv_train_precisions.append(np.mean(fold_train_prec))
- cv_val_precisions.append(np.mean(fold_val_prec))
- cv_test_precisions.append(test_prec)
- cv_train_recalls.append(np.mean(fold_train_rec))
- cv_val_recalls.append(np.mean(fold_val_rec))
- cv_test_recalls.append(test_rec)
- cv_train_f1s.append(np.mean(fold_train_f1))
- cv_val_f1s.append(np.mean(fold_val_f1))
- cv_test_f1s.append(test_f1)
- # %%
- import pandas as pd
- # Conversion des scores en pourcentages
- test_accuracies_percent = [acc * 100 for acc in cv_test_accuracies]
- test_precisions_percent = [prec * 100 for prec in cv_test_precisions]
- test_recalls_percent = [rec * 100 for rec in cv_test_recalls]
- test_f1_scores_percent = [f1 * 100 for f1 in cv_test_f1s]
- # Création d'un DataFrame avec les scores
- results_df = pd.DataFrame({
- "Subject": [f"Person {i+1}" for i in range(len(test_accuracies_percent))],
- "Accuracy (%)": test_accuracies_percent,
- "Precision (%)": test_precisions_percent,
- "Recall (%)": test_recalls_percent,
- "F1-score (%)": test_f1_scores_percent
- })
- # Arrondir les valeurs à 2 décimales
- results_df = results_df.round(2)
- # Affichage du tableau
- print("\nTest Metrics per Subject:\n")
- print(results_df.to_string(index=False))
- # Moyennes globales
- average_results = results_df.mean(numeric_only=True)
- print("\nAverage Test Metrics Across All Subjects:")
- print(f"Accuracy: {average_results['Accuracy (%)']:.2f}%")
- print(f"Precision: {average_results['Precision (%)']:.2f}%")
- print(f"Recall: {average_results['Recall (%)']:.2f}%")
- print(f"F1-score: {average_results['F1-score (%)']:.2f}%")
- # %% [markdown]
- # # RFC Classification
- # %%
- from sklearn.model_selection import KFold
- from sklearn.preprocessing import StandardScaler
- from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
- from sklearn.pipeline import make_pipeline
- import numpy as np
- from sklearn.ensemble import RandomForestClassifier
- # Initialisation des listes
- cv_train_accuracies, cv_val_accuracies, cv_test_accuracies = [], [], []
- cv_train_precisions, cv_val_precisions, cv_test_precisions = [], [], []
- cv_train_recalls, cv_val_recalls, cv_test_recalls = [], [], []
- cv_train_f1s, cv_val_f1s, cv_test_f1s = [], [], []
- kfold = KFold(n_splits=5, shuffle=True, random_state=42)
- for i, (features_train, y_labels_T, features_test, y_labels_E) in enumerate(zip(all_person_featuresT, all_y_labels_T,
- all_person_featuresE, all_y_labels_E)):
- print(f"\nProcessing subject {i + 1}")
- # Pour accumuler les scores par pli
- fold_train_accs, fold_val_accs = [], []
- fold_train_prec, fold_val_prec = [], []
- fold_train_rec, fold_val_rec = [], []
- fold_train_f1, fold_val_f1 = [], []
- model = make_pipeline(StandardScaler(),
- RandomForestClassifier(n_estimators=100, class_weight='balanced', random_state=42))
- # Validation croisée
- for train_idx, val_idx in kfold.split(features_train):
- X_train_fold, X_val_fold = features_train[train_idx], features_train[val_idx]
- y_train_fold, y_val_fold = y_labels_T[train_idx], y_labels_T[val_idx]
- model.fit(X_train_fold, y_train_fold)
- # Prédictions
- y_train_pred = model.predict(X_train_fold)
- y_val_pred = model.predict(X_val_fold)
- # Accuracy
- fold_train_accs.append(accuracy_score(y_train_fold, y_train_pred))
- fold_val_accs.append(accuracy_score(y_val_fold, y_val_pred))
- # Precision, Recall, F1
- fold_train_prec.append(precision_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_prec.append(precision_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_rec.append(recall_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_rec.append(recall_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_f1.append(f1_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_f1.append(f1_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- # Réentraînement sur tout l'ensemble d'apprentissage
- model.fit(features_train, y_labels_T)
- y_test_pred = model.predict(features_test)
- # Test scores
- test_acc = accuracy_score(y_labels_E, y_test_pred)
- test_prec = precision_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_rec = recall_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_f1 = f1_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- # Moyennes sur les plis
- cv_train_accuracies.append(np.mean(fold_train_accs))
- cv_val_accuracies.append(np.mean(fold_val_accs))
- cv_test_accuracies.append(test_acc)
- cv_train_precisions.append(np.mean(fold_train_prec))
- cv_val_precisions.append(np.mean(fold_val_prec))
- cv_test_precisions.append(test_prec)
- cv_train_recalls.append(np.mean(fold_train_rec))
- cv_val_recalls.append(np.mean(fold_val_rec))
- cv_test_recalls.append(test_rec)
- cv_train_f1s.append(np.mean(fold_train_f1))
- cv_val_f1s.append(np.mean(fold_val_f1))
- cv_test_f1s.append(test_f1)
- # %%
- import pandas as pd
- # Conversion des scores en pourcentages
- test_accuracies_percent = [acc * 100 for acc in cv_test_accuracies]
- test_precisions_percent = [prec * 100 for prec in cv_test_precisions]
- test_recalls_percent = [rec * 100 for rec in cv_test_recalls]
- test_f1_scores_percent = [f1 * 100 for f1 in cv_test_f1s]
- # Création d'un DataFrame avec les scores
- results_df = pd.DataFrame({
- "Subject": [f"Person {i+1}" for i in range(len(test_accuracies_percent))],
- "Accuracy (%)": test_accuracies_percent,
- "Precision (%)": test_precisions_percent,
- "Recall (%)": test_recalls_percent,
- "F1-score (%)": test_f1_scores_percent
- })
- # Arrondir les valeurs à 2 décimales
- results_df = results_df.round(2)
- # Affichage du tableau
- print("\nTest Metrics per Subject:\n")
- print(results_df.to_string(index=False))
- # Moyennes globales
- average_results = results_df.mean(numeric_only=True)
- print("\nAverage Test Metrics Across All Subjects:")
- print(f"Accuracy: {average_results['Accuracy (%)']:.2f}%")
- print(f"Precision: {average_results['Precision (%)']:.2f}%")
- print(f"Recall: {average_results['Recall (%)']:.2f}%")
- print(f"F1-score: {average_results['F1-score (%)']:.2f}%")
- # %% [markdown]
- # # MLP classification
- # %%
- from sklearn.model_selection import KFold
- from sklearn.preprocessing import StandardScaler
- from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
- from sklearn.pipeline import make_pipeline
- import numpy as np
- from sklearn.ensemble import RandomForestClassifier
- from sklearn.neural_network import MLPClassifier
- # Initialisation des listes
- cv_train_accuracies, cv_val_accuracies, cv_test_accuracies = [], [], []
- cv_train_precisions, cv_val_precisions, cv_test_precisions = [], [], []
- cv_train_recalls, cv_val_recalls, cv_test_recalls = [], [], []
- cv_train_f1s, cv_val_f1s, cv_test_f1s = [], [], []
- kfold = KFold(n_splits=5, shuffle=True, random_state=42)
- for i, (features_train, y_labels_T, features_test, y_labels_E) in enumerate(zip(all_person_featuresT, all_y_labels_T,
- all_person_featuresE, all_y_labels_E)):
- print(f"\nProcessing subject {i + 1}")
- # Pour accumuler les scores par pli
- fold_train_accs, fold_val_accs = [], []
- fold_train_prec, fold_val_prec = [], []
- fold_train_rec, fold_val_rec = [], []
- fold_train_f1, fold_val_f1 = [], []
- model = make_pipeline(StandardScaler(),
- MLPClassifier(hidden_layer_sizes=(100,), max_iter=300, activation='tanh', solver='adam',
- learning_rate_init=0.001, random_state=42 ))
- # Validation croisée
- for train_idx, val_idx in kfold.split(features_train):
- X_train_fold, X_val_fold = features_train[train_idx], features_train[val_idx]
- y_train_fold, y_val_fold = y_labels_T[train_idx], y_labels_T[val_idx]
- model.fit(X_train_fold, y_train_fold)
- # Prédictions
- y_train_pred = model.predict(X_train_fold)
- y_val_pred = model.predict(X_val_fold)
- # Accuracy
- fold_train_accs.append(accuracy_score(y_train_fold, y_train_pred))
- fold_val_accs.append(accuracy_score(y_val_fold, y_val_pred))
- # Precision, Recall, F1
- fold_train_prec.append(precision_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_prec.append(precision_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_rec.append(recall_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_rec.append(recall_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_f1.append(f1_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_f1.append(f1_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- # Réentraînement sur tout l'ensemble d'apprentissage
- model.fit(features_train, y_labels_T)
- y_test_pred = model.predict(features_test)
- # Test scores
- test_acc = accuracy_score(y_labels_E, y_test_pred)
- test_prec = precision_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_rec = recall_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_f1 = f1_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- # Moyennes sur les plis
- cv_train_accuracies.append(np.mean(fold_train_accs))
- cv_val_accuracies.append(np.mean(fold_val_accs))
- cv_test_accuracies.append(test_acc)
- cv_train_precisions.append(np.mean(fold_train_prec))
- cv_val_precisions.append(np.mean(fold_val_prec))
- cv_test_precisions.append(test_prec)
- cv_train_recalls.append(np.mean(fold_train_rec))
- cv_val_recalls.append(np.mean(fold_val_rec))
- cv_test_recalls.append(test_rec)
- cv_train_f1s.append(np.mean(fold_train_f1))
- cv_val_f1s.append(np.mean(fold_val_f1))
- cv_test_f1s.append(test_f1)
- # %%
- import pandas as pd
- # Conversion des scores en pourcentages
- test_accuracies_percent = [acc * 100 for acc in cv_test_accuracies]
- test_precisions_percent = [prec * 100 for prec in cv_test_precisions]
- test_recalls_percent = [rec * 100 for rec in cv_test_recalls]
- test_f1_scores_percent = [f1 * 100 for f1 in cv_test_f1s]
- # Création d'un DataFrame avec les scores
- results_df = pd.DataFrame({
- "Subject": [f"Person {i+1}" for i in range(len(test_accuracies_percent))],
- "Accuracy (%)": test_accuracies_percent,
- "Precision (%)": test_precisions_percent,
- "Recall (%)": test_recalls_percent,
- "F1-score (%)": test_f1_scores_percent
- })
- # Arrondir les valeurs à 2 décimales
- results_df = results_df.round(2)
- # Affichage du tableau
- print("\nTest Metrics per Subject:\n")
- print(results_df.to_string(index=False))
- # Moyennes globales
- average_results = results_df.mean(numeric_only=True)
- print("\nAverage Test Metrics Across All Subjects:")
- print(f"Accuracy: {average_results['Accuracy (%)']:.2f}%")
- print(f"Precision: {average_results['Precision (%)']:.2f}%")
- print(f"Recall: {average_results['Recall (%)']:.2f}%")
- print(f"F1-score: {average_results['F1-score (%)']:.2f}%")
- # %% [markdown]
- # # Multiband filtering
- # %%
- def process_bands(data, bands, fs, order, n_components, labels):
- all_features = []
- for band in bands:
- lowcut, highcut = band
- # Étape 1 : Filtrage des données pour la bande actuelle
- filtered_data = my_filter_function(data, lowcut, highcut, fs, order)
- # Étape 2 : Extraction des caractéristiques CSP
- csp_features, _ = CSP_OVR_optim(filtered_data, labels, n_components)
- # Ajouter les caractéristiques de cette bande
- all_features.append(csp_features)
- # Étape 3 : Combiner les caractéristiques de toutes les bandes
- combined_features = np.concatenate(all_features, axis=1)
- return combined_features
- # %%
- # %%capture
- all_person_featuresT = []
- all_person_featuresE = []
- order_filter=6
- lowcut =8.0
- highcut =30.0
- fs=250
- n_components_csp=22
- bands = [(8, 12), (12, 30), (30, 45)]
- i=0
- # Loop on each person for Train data
- for person_index, (x_data_T, y_labels_T) in enumerate(zip(all_x_data_T, all_y_labels_T)):
- i=i+1
- print(i)
- # CSPPP
- CSP_T= process_bands(x_data_T, bands, fs, order_filter, n_components_csp, y_labels_T)
- all_person_featuresT.append(CSP_T)
- i=0
- # Loop on each person for test data
- for person_index, (x_data_E, y_labels_E) in enumerate(zip(all_x_data_E, all_y_labels_E)):
- i=i+1
- print(i)
- # CSPPP
- CSP_E=process_bands(x_data_E, bands, fs, order_filter, n_components_csp, y_labels_E)
- all_person_featuresE.append(CSP_E)
- # Convertissez les listes en tableaux numpy
- all_person_featuresT = np.array(all_person_featuresT)
- all_person_featuresE = np.array(all_person_featuresE)
- # %% [markdown]
- # # LDA classification
- # %%
- from sklearn.model_selection import KFold
- from sklearn.preprocessing import StandardScaler
- from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
- from sklearn.pipeline import make_pipeline
- import numpy as np
- # Initialisation des listes
- cv_train_accuracies, cv_val_accuracies, cv_test_accuracies = [], [], []
- cv_train_precisions, cv_val_precisions, cv_test_precisions = [], [], []
- cv_train_recalls, cv_val_recalls, cv_test_recalls = [], [], []
- cv_train_f1s, cv_val_f1s, cv_test_f1s = [], [], []
- kfold = KFold(n_splits=5, shuffle=True, random_state=42)
- for i, (features_train, y_labels_T, features_test, y_labels_E) in enumerate(zip(all_person_featuresT, all_y_labels_T,
- all_person_featuresE, all_y_labels_E)):
- print(f"\nProcessing subject {i + 1}")
- # Pour accumuler les scores par pli
- fold_train_accs, fold_val_accs = [], []
- fold_train_prec, fold_val_prec = [], []
- fold_train_rec, fold_val_rec = [], []
- fold_train_f1, fold_val_f1 = [], []
- model = make_pipeline(StandardScaler(),
- LinearDiscriminantAnalysis(solver='lsqr', shrinkage='auto',
- n_components=3, tol=1e-4))
- # Validation croisée
- for train_idx, val_idx in kfold.split(features_train):
- X_train_fold, X_val_fold = features_train[train_idx], features_train[val_idx]
- y_train_fold, y_val_fold = y_labels_T[train_idx], y_labels_T[val_idx]
- model.fit(X_train_fold, y_train_fold)
- # Prédictions
- y_train_pred = model.predict(X_train_fold)
- y_val_pred = model.predict(X_val_fold)
- # Accuracy
- fold_train_accs.append(accuracy_score(y_train_fold, y_train_pred))
- fold_val_accs.append(accuracy_score(y_val_fold, y_val_pred))
- # Precision, Recall, F1
- fold_train_prec.append(precision_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_prec.append(precision_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_rec.append(recall_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_rec.append(recall_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_f1.append(f1_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_f1.append(f1_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- # Réentraînement sur tout l'ensemble d'apprentissage
- model.fit(features_train, y_labels_T)
- y_test_pred = model.predict(features_test)
- # Test scores
- test_acc = accuracy_score(y_labels_E, y_test_pred)
- test_prec = precision_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_rec = recall_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_f1 = f1_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- # Moyennes sur les plis
- cv_train_accuracies.append(np.mean(fold_train_accs))
- cv_val_accuracies.append(np.mean(fold_val_accs))
- cv_test_accuracies.append(test_acc)
- cv_train_precisions.append(np.mean(fold_train_prec))
- cv_val_precisions.append(np.mean(fold_val_prec))
- cv_test_precisions.append(test_prec)
- cv_train_recalls.append(np.mean(fold_train_rec))
- cv_val_recalls.append(np.mean(fold_val_rec))
- cv_test_recalls.append(test_rec)
- cv_train_f1s.append(np.mean(fold_train_f1))
- cv_val_f1s.append(np.mean(fold_val_f1))
- cv_test_f1s.append(test_f1)
- # %%
- import pandas as pd
- # Conversion des scores en pourcentages
- test_accuracies_percent = [acc * 100 for acc in cv_test_accuracies]
- test_precisions_percent = [prec * 100 for prec in cv_test_precisions]
- test_recalls_percent = [rec * 100 for rec in cv_test_recalls]
- test_f1_scores_percent = [f1 * 100 for f1 in cv_test_f1s]
- # Création d'un DataFrame avec les scores
- results_df = pd.DataFrame({
- "Subject": [f"Person {i+1}" for i in range(len(test_accuracies_percent))],
- "Accuracy (%)": test_accuracies_percent,
- "Precision (%)": test_precisions_percent,
- "Recall (%)": test_recalls_percent,
- "F1-score (%)": test_f1_scores_percent
- })
- # Arrondir les valeurs à 2 décimales
- results_df = results_df.round(2)
- # Affichage du tableau
- print("\nTest Metrics per Subject:\n")
- print(results_df.to_string(index=False))
- # Moyennes globales
- average_results = results_df.mean(numeric_only=True)
- print("\nAverage Test Metrics Across All Subjects:")
- print(f"Accuracy: {average_results['Accuracy (%)']:.2f}%")
- print(f"Precision: {average_results['Precision (%)']:.2f}%")
- print(f"Recall: {average_results['Recall (%)']:.2f}%")
- print(f"F1-score: {average_results['F1-score (%)']:.2f}%")
- # %% [markdown]
- # # RFC classification
- # %%
- from sklearn.model_selection import KFold
- from sklearn.preprocessing import StandardScaler
- from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
- from sklearn.pipeline import make_pipeline
- import numpy as np
- from sklearn.ensemble import RandomForestClassifier
- # Initialisation des listes
- cv_train_accuracies, cv_val_accuracies, cv_test_accuracies = [], [], []
- cv_train_precisions, cv_val_precisions, cv_test_precisions = [], [], []
- cv_train_recalls, cv_val_recalls, cv_test_recalls = [], [], []
- cv_train_f1s, cv_val_f1s, cv_test_f1s = [], [], []
- kfold = KFold(n_splits=5, shuffle=True, random_state=42)
- for i, (features_train, y_labels_T, features_test, y_labels_E) in enumerate(zip(all_person_featuresT, all_y_labels_T,
- all_person_featuresE, all_y_labels_E)):
- print(f"\nProcessing subject {i + 1}")
- # Pour accumuler les scores par pli
- fold_train_accs, fold_val_accs = [], []
- fold_train_prec, fold_val_prec = [], []
- fold_train_rec, fold_val_rec = [], []
- fold_train_f1, fold_val_f1 = [], []
- model = make_pipeline(StandardScaler(),
- RandomForestClassifier(n_estimators=100, random_state=42))
- # Validation croisée
- for train_idx, val_idx in kfold.split(features_train):
- X_train_fold, X_val_fold = features_train[train_idx], features_train[val_idx]
- y_train_fold, y_val_fold = y_labels_T[train_idx], y_labels_T[val_idx]
- model.fit(X_train_fold, y_train_fold)
- # Prédictions
- y_train_pred = model.predict(X_train_fold)
- y_val_pred = model.predict(X_val_fold)
- # Accuracy
- fold_train_accs.append(accuracy_score(y_train_fold, y_train_pred))
- fold_val_accs.append(accuracy_score(y_val_fold, y_val_pred))
- # Precision, Recall, F1
- fold_train_prec.append(precision_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_prec.append(precision_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_rec.append(recall_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_rec.append(recall_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_f1.append(f1_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_f1.append(f1_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- # Réentraînement sur tout l'ensemble d'apprentissage
- model.fit(features_train, y_labels_T)
- y_test_pred = model.predict(features_test)
- # Test scores
- test_acc = accuracy_score(y_labels_E, y_test_pred)
- test_prec = precision_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_rec = recall_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_f1 = f1_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- # Moyennes sur les plis
- cv_train_accuracies.append(np.mean(fold_train_accs))
- cv_val_accuracies.append(np.mean(fold_val_accs))
- cv_test_accuracies.append(test_acc)
- cv_train_precisions.append(np.mean(fold_train_prec))
- cv_val_precisions.append(np.mean(fold_val_prec))
- cv_test_precisions.append(test_prec)
- cv_train_recalls.append(np.mean(fold_train_rec))
- cv_val_recalls.append(np.mean(fold_val_rec))
- cv_test_recalls.append(test_rec)
- cv_train_f1s.append(np.mean(fold_train_f1))
- cv_val_f1s.append(np.mean(fold_val_f1))
- cv_test_f1s.append(test_f1)
- # %%
- import pandas as pd
- # Conversion des scores en pourcentages
- test_accuracies_percent = [acc * 100 for acc in cv_test_accuracies]
- test_precisions_percent = [prec * 100 for prec in cv_test_precisions]
- test_recalls_percent = [rec * 100 for rec in cv_test_recalls]
- test_f1_scores_percent = [f1 * 100 for f1 in cv_test_f1s]
- # Création d'un DataFrame avec les scores
- results_df = pd.DataFrame({
- "Subject": [f"Person {i+1}" for i in range(len(test_accuracies_percent))],
- "Accuracy (%)": test_accuracies_percent,
- "Precision (%)": test_precisions_percent,
- "Recall (%)": test_recalls_percent,
- "F1-score (%)": test_f1_scores_percent
- })
- # Arrondir les valeurs à 2 décimales
- results_df = results_df.round(2)
- # Affichage du tableau
- print("\nTest Metrics per Subject:\n")
- print(results_df.to_string(index=False))
- # Moyennes globales
- average_results = results_df.mean(numeric_only=True)
- print("\nAverage Test Metrics Across All Subjects:")
- print(f"Accuracy: {average_results['Accuracy (%)']:.2f}%")
- print(f"Precision: {average_results['Precision (%)']:.2f}%")
- print(f"Recall: {average_results['Recall (%)']:.2f}%")
- print(f"F1-score: {average_results['F1-score (%)']:.2f}%")
- # %% [markdown]
- # # MLP classification
- # %%
- from sklearn.model_selection import KFold
- from sklearn.preprocessing import StandardScaler
- from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
- from sklearn.pipeline import make_pipeline
- import numpy as np
- from sklearn.ensemble import RandomForestClassifier
- from sklearn.neural_network import MLPClassifier
- # Initialisation des listes
- cv_train_accuracies, cv_val_accuracies, cv_test_accuracies = [], [], []
- cv_train_precisions, cv_val_precisions, cv_test_precisions = [], [], []
- cv_train_recalls, cv_val_recalls, cv_test_recalls = [], [], []
- cv_train_f1s, cv_val_f1s, cv_test_f1s = [], [], []
- kfold = KFold(n_splits=5, shuffle=True, random_state=42)
- for i, (features_train, y_labels_T, features_test, y_labels_E) in enumerate(zip(all_person_featuresT, all_y_labels_T,
- all_person_featuresE, all_y_labels_E)):
- print(f"\nProcessing subject {i + 1}")
- # Pour accumuler les scores par pli
- fold_train_accs, fold_val_accs = [], []
- fold_train_prec, fold_val_prec = [], []
- fold_train_rec, fold_val_rec = [], []
- fold_train_f1, fold_val_f1 = [], []
- model = make_pipeline(StandardScaler(),
- MLPClassifier(hidden_layer_sizes=(100,), max_iter=300, activation='tanh', solver='adam',
- learning_rate_init=0.001, random_state=42 ))
- # Validation croisée
- for train_idx, val_idx in kfold.split(features_train):
- X_train_fold, X_val_fold = features_train[train_idx], features_train[val_idx]
- y_train_fold, y_val_fold = y_labels_T[train_idx], y_labels_T[val_idx]
- model.fit(X_train_fold, y_train_fold)
- # Prédictions
- y_train_pred = model.predict(X_train_fold)
- y_val_pred = model.predict(X_val_fold)
- # Accuracy
- fold_train_accs.append(accuracy_score(y_train_fold, y_train_pred))
- fold_val_accs.append(accuracy_score(y_val_fold, y_val_pred))
- # Precision, Recall, F1
- fold_train_prec.append(precision_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_prec.append(precision_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_rec.append(recall_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_rec.append(recall_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- fold_train_f1.append(f1_score(y_train_fold, y_train_pred, average='weighted', zero_division=0))
- fold_val_f1.append(f1_score(y_val_fold, y_val_pred, average='weighted', zero_division=0))
- # Réentraînement sur tout l'ensemble d'apprentissage
- model.fit(features_train, y_labels_T)
- y_test_pred = model.predict(features_test)
- # Test scores
- test_acc = accuracy_score(y_labels_E, y_test_pred)
- test_prec = precision_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_rec = recall_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- test_f1 = f1_score(y_labels_E, y_test_pred, average='weighted', zero_division=0)
- # Moyennes sur les plis
- cv_train_accuracies.append(np.mean(fold_train_accs))
- cv_val_accuracies.append(np.mean(fold_val_accs))
- cv_test_accuracies.append(test_acc)
- cv_train_precisions.append(np.mean(fold_train_prec))
- cv_val_precisions.append(np.mean(fold_val_prec))
- cv_test_precisions.append(test_prec)
- cv_train_recalls.append(np.mean(fold_train_rec))
- cv_val_recalls.append(np.mean(fold_val_rec))
- cv_test_recalls.append(test_rec)
- cv_train_f1s.append(np.mean(fold_train_f1))
- cv_val_f1s.append(np.mean(fold_val_f1))
- cv_test_f1s.append(test_f1)
- # %%
- import pandas as pd
- # Conversion des scores en pourcentages
- test_accuracies_percent = [acc * 100 for acc in cv_test_accuracies]
- test_precisions_percent = [prec * 100 for prec in cv_test_precisions]
- test_recalls_percent = [rec * 100 for rec in cv_test_recalls]
- test_f1_scores_percent = [f1 * 100 for f1 in cv_test_f1s]
- # Création d'un DataFrame avec les scores
- results_df = pd.DataFrame({
- "Subject": [f"Person {i+1}" for i in range(len(test_accuracies_percent))],
- "Accuracy (%)": test_accuracies_percent,
- "Precision (%)": test_precisions_percent,
- "Recall (%)": test_recalls_percent,
- "F1-score (%)": test_f1_scores_percent
- })
- # Arrondir les valeurs à 2 décimales
- results_df = results_df.round(2)
- # Affichage du tableau
- print("\nTest Metrics per Subject:\n")
- print(results_df.to_string(index=False))
- # Moyennes globales
- average_results = results_df.mean(numeric_only=True)
- print("\nAverage Test Metrics Across All Subjects:")
- print(f"Accuracy: {average_results['Accuracy (%)']:.2f}%")
- print(f"Precision: {average_results['Precision (%)']:.2f}%")
- print(f"Recall: {average_results['Recall (%)']:.2f}%")
- print(f"F1-score: {average_results['F1-score (%)']:.2f}%")
- # %% [markdown]
- # # votting simple
- # %%
- from sklearn.ensemble import VotingClassifier
- from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
- from sklearn.neural_network import MLPClassifier
- from sklearn.ensemble import RandomForestClassifier
- from sklearn.pipeline import make_pipeline
- from sklearn.preprocessing import StandardScaler
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
- # Initialisation des listes pour stocker les performances
- voting_accuracies, voting_precisions, voting_recalls, voting_f1_scores = [], [], [], []
- # Boucle sur chaque personne
- for i, (X_train, y_train, X_test, y_test) in enumerate(zip(all_person_featuresT, all_y_labels_T,
- all_person_featuresE, all_y_labels_E)):
- print(f"\n>>> Voting classifier - Subject {i + 1}")
- # Définition des 3 classificateurs de base
- lda = make_pipeline(StandardScaler(), LinearDiscriminantAnalysis(solver='lsqr', shrinkage='auto', n_components=3, tol=1e-4))
- rf = make_pipeline(StandardScaler(), RandomForestClassifier(n_estimators=100, random_state=42))
- mlp = make_pipeline(StandardScaler(),MLPClassifier(hidden_layer_sizes=(100,), max_iter=300, activation='tanh', solver='adam',
- learning_rate_init=0.001, random_state=42 ))
- # Voting classifier (majority vote)
- voting_clf = VotingClassifier(estimators=[
- ('lda', lda),
- ('mlp', mlp),
- ('rf', rf)
- ], voting='hard')
- # Entraînement
- voting_clf.fit(X_train, y_train)
- # Prédiction
- y_pred = voting_clf.predict(X_test)
- # Évaluation
- acc = accuracy_score(y_test, y_pred)
- prec = precision_score(y_test, y_pred, average='weighted', zero_division=0)
- rec = recall_score(y_test, y_pred, average='weighted', zero_division=0)
- f1 = f1_score(y_test, y_pred, average='weighted', zero_division=0)
- # Stockage
- voting_accuracies.append(acc)
- voting_precisions.append(prec)
- voting_recalls.append(rec)
- voting_f1_scores.append(f1)
- # Résultats moyens
- print("\n>>> Voting Classifier - Average Test Metrics:")
- print(f"Accuracy: {np.mean(voting_accuracies) * 100:.2f}%")
- print(f"Precision: {np.mean(voting_precisions) * 100:.2f}%")
- print(f"Recall: {np.mean(voting_recalls) * 100:.2f}%")
- print(f"F1-score: {np.mean(voting_f1_scores) * 100:.2f}%")
- # %% [markdown]
- # # votting+ Cross validation
- # %%
- from sklearn.ensemble import VotingClassifier
- from sklearn.model_selection import cross_val_score
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
- # Initialisation des métriques
- metrics = {
- 'subject': [], 'acc': [], 'prec': [], 'rec': [], 'f1': [],
- 'cv_acc_mean': [], 'cv_acc_std': []
- }
- for i, (X_train, y_train, X_test, y_test) in enumerate(zip(all_person_featuresT, all_y_labels_T,
- all_person_featuresE, all_y_labels_E)):
- print(f"\n>>> Subject {i + 1}")
- # Définition des classifieurs
- lda = make_pipeline(StandardScaler(), LinearDiscriminantAnalysis(solver='lsqr', shrinkage='auto'))
- rf = make_pipeline(StandardScaler(), RandomForestClassifier(n_estimators=100, class_weight='balanced', random_state=42))
- mlp = make_pipeline(StandardScaler(), MLPClassifier(hidden_layer_sizes=(100,), max_iter=300, early_stopping=True, random_state=42))
- # Voting Classifier
- voting_clf = VotingClassifier(
- estimators=[('lda', lda), ('rf', rf), ('mlp', mlp)],
- voting='soft' # ou 'hard'
- )
- # Validation croisée
- cv_scores = cross_val_score(voting_clf, X_train, y_train, cv=5, scoring='accuracy')
- metrics['cv_acc_mean'].append(np.mean(cv_scores))
- metrics['cv_acc_std'].append(np.std(cv_scores))
- # Entraînement final
- voting_clf.fit(X_train, y_train)
- y_pred = voting_clf.predict(X_test)
- # Stockage des résultats
- metrics['subject'].append(i+1)
- metrics['acc'].append(accuracy_score(y_test, y_pred))
- metrics['prec'].append(precision_score(y_test, y_pred, average='weighted', zero_division=0))
- metrics['rec'].append(recall_score(y_test, y_pred, average='weighted', zero_division=0))
- metrics['f1'].append(f1_score(y_test, y_pred, average='weighted', zero_division=0))
- # Affichage détaillé
- print(f"CV Accuracy: {metrics['cv_acc_mean'][-1]:.3f} ± {metrics['cv_acc_std'][-1]:.3f}")
- print(f"Test Accuracy: {metrics['acc'][-1]:.3f}")
- # Résultats finaux
- print("\n>>> Final Metrics <<<")
- print(f"Mean Test Accuracy: {np.mean(metrics['acc']) * 100:.2f}%")
- print(f"Mean Test Precision: {np.mean(metrics['prec']) * 100:.2f}%")
- print(f"Mean Test Recall: {np.mean(metrics['rec']) * 100:.2f}%")
- print(f"Mean Test F1-score: {np.mean(metrics['f1']) * 100:.2f}%")
- # %%
- from sklearn.ensemble import VotingClassifier
- from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
- from sklearn.neural_network import MLPClassifier
- from sklearn.ensemble import RandomForestClassifier
- from sklearn.pipeline import make_pipeline
- from sklearn.preprocessing import StandardScaler
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
- from collections import Counter
- import numpy as np
- # Initialisation des listes pour stocker les performances
- voting_accuracies, voting_precisions, voting_recalls, voting_f1_scores = [], [], [], []
- # Boucle sur chaque personne
- for i, (X_train, y_train, X_test, y_test) in enumerate(zip(all_person_featuresT, all_y_labels_T,
- all_person_featuresE, all_y_labels_E)):
- print(f"\n>>> Voting classifier - Subject {i + 1}")
- # Définition des 3 classificateurs de base
- lda = make_pipeline(StandardScaler(), LinearDiscriminantAnalysis(solver='lsqr', shrinkage='auto'))
- rf = make_pipeline(StandardScaler(), RandomForestClassifier(n_estimators=100, random_state=42))
- mlp = make_pipeline(StandardScaler(), MLPClassifier(hidden_layer_sizes=(100,), max_iter=300,
- activation='tanh', solver='adam',
- learning_rate_init=0.001, random_state=42))
- # Voting classifier (majority vote)
- voting_clf = VotingClassifier(estimators=[
- ('lda', lda),
- ('mlp', mlp),
- ('rf', rf)
- ], voting='hard') # Pour vote majoritaire
- # Entraînement
- voting_clf.fit(X_train, y_train)
- # Prédiction finale
- y_pred = voting_clf.predict(X_test)
- # Évaluation
- acc = accuracy_score(y_test, y_pred)
- prec = precision_score(y_test, y_pred, average='weighted', zero_division=0)
- rec = recall_score(y_test, y_pred, average='weighted', zero_division=0)
- f1 = f1_score(y_test, y_pred, average='weighted', zero_division=0)
- # Stockage des métriques
- voting_accuracies.append(acc)
- voting_precisions.append(prec)
- voting_recalls.append(rec)
- voting_f1_scores.append(f1)
- # Prédictions individuelles
- lda_pred = voting_clf.named_estimators_['lda'].predict(X_test)
- mlp_pred = voting_clf.named_estimators_['mlp'].predict(X_test)
- rf_pred = voting_clf.named_estimators_['rf'].predict(X_test)
- # Affichage des votes pour les 10 premiers échantillons
- print("\nIndividual classifier decisions (first 10 samples) :")
- print("Index | LDA | MLP | RF | Final Decision | Majority vote")
- print("------------------------------------------------------------")
- for j in range(min(10, len(X_test))):
- votes = [lda_pred[j], mlp_pred[j], rf_pred[j]]
- vote_count = Counter(votes)
- majority_class, count = vote_count.most_common(1)[0]
- print(f"{j:5d} | {lda_pred[j]:3} | {mlp_pred[j]:3} | {rf_pred[j]:3} | {y_pred[j]:14} | {majority_class} ({count} votes)")
- # Résultats moyens sur tous les sujets
- print("\n>>> Voting Classifier - Average Test Metrics:")
- print(f"Accuracy: {np.mean(voting_accuracies) * 100:.2f}%")
- print(f"Precision: {np.mean(voting_precisions) * 100:.2f}%")
- print(f"Recall: {np.mean(voting_recalls) * 100:.2f}%")
- print(f"F1-score: {np.mean(voting_f1_scores) * 100:.2f}%")
- # %%
BCI_R-FBCSP.ipynb, under CC-BY-4.0 · at the source
Overview
- ATMS Laboratory, National Engineering School of Sfax, University of Sfax,Sfax, Tunisia
- Laboratory of Electronics and Microelectronics (FSM), University of Monastir,Monastir, Tunisia
- Higher Institute of Applied Sciences and Technology of Sousse, University of Sousse,Sousse, Tunisia
- Department of Computer Engineering, College of Computing and Informatics, University of Sharjah,Sharjah, UAE
- Department of Computer Science, College of Computing and Informatics, University of Sharjah,Sharjah, UAE
Abstract
The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.
Repositories
Its files are read in the Code ↔ Paper reader above, with 1 match between paragraphs and lines of code.
Zenodo 15825805
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
- 30 September 2026: the link answers (HTTP 200)
souissijihen/BCI_RW_FBCSP_GigaDB
Availability: 1 check, the latest on 30 September 2026: the link is dead
- 30 September 2026: the link is dead
Zenodo 15828534
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
- 30 September 2026: the link answers (HTTP 200)
4 files
- BCI_R-FBCSP.ipynb, Jupyter, 1,259 lines, 1 match
- BCI_RW-FBCSP.ipynb, Jupyter, 1,212 lines
- CSP_jrnl_affichage .ipynb, Jupyter, 638 lines
- README.md, Text, 19 lines
souissijihen/bci_rw_fbcsp-
Availability: 1 check, the latest on 30 September 2026: the link is dead
- 30 September 2026: the link is dead
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 4 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 3 scripts, each with its path and the digest of its content;
- 1 match between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
- bbci.de/
competition/ , at bbci.de; found in the referencesiv
Data availability statement
The paper has a data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- no repository, dataset or request procedure was recognized in it
Read it in the paper: doi.org/10.1186/s40708-026-00295-0.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 30 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 5 authors, 6 keywords, 1 funder, 36 references, 6 RRIDs.
Cite
This paper
Jihen, S., Karmani, S., Belwafi, K., Jemmali, M., & Djemal, R. (2026). Filter bank CSP with Riemannian weighting for disability-centric motor imagery brain computer interface. Brain informatics, 13(1), 12. https://
BibTeX
@article{jihen2026filter
author = {Jihen, Souissi and Karmani, Sourour and Belwafi, Kais and Jemmali, Mahdi and Djemal, Ridha},
title = {{Filter bank CSP with Riemannian weighting for disability-centric motor imagery brain computer interface}},
journal = {Brain informatics},
year = {2026},
month = mar,
volume = {13},
number = {1},
pages = {12},
publisher = {Springer},
issn = {2198-4018},
doi = {10.1186/
url = {https://
pmid = {41886201},
pmcid = {PMC13133326}
}
RIS
TY - JOUR
AU - Jihen, Souissi
AU - Karmani, Sourour
AU - Belwafi, Kais
AU - Jemmali, Mahdi
AU - Djemal, Ridha
TI - Filter bank CSP with Riemannian weighting for disability-centric motor imagery brain computer interface
T2 - Brain informatics
J2 - Brain Inform
PY - 2026
DA - 2026/
VL - 13
IS - 1
SP - 12
SN - 2198-4018
PB - Springer
DO - 10.1186/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1186/
"type": "article-journal",
"title": "Filter bank CSP with Riemannian weighting for disability-centric motor imagery brain computer interface",
"container-title": "Brain informatics",
"author": [
{
"family": "Jihen",
"given": "Souissi"
},
{
"family": "Karmani",
"given": "Sourour"
},
{
"family": "Belwafi",
"given": "Kais"
},
{
"family": "Jemmali",
"given": "Mahdi"
},
{
"family": "Djemal",
"given": "Ridha"
}
],
"container-title-short":
"volume": "13",
"issue": "1",
"page": "12",
"DOI": "10.1186/
"PMID": "41886201",
"PMCID": "PMC13133326",
"ISSN": "2198-4018",
"publisher": "Springer",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
26
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41598-024-73755-4 [code]
- Compact convolutional transformer for subject-independent motor imagery EEG-based BCIs.Journal: Scientific reportsIn common: MNE-Python, scikit-learn, pandas, 3 other tools, bbci.de/competition/iv, methods / tools, EEG, 5 references
- [2] doi:10.3390/brainsci15010027 [code]
- A Task-Related EEG Microstate Clustering Algorithm Based on Spatial Patterns, Riemannian Distance, and a Deep Autoencoder.Journal: Brain sciencesIn common: MNE-Python, scikit-learn, pandas, 3 other tools, EEG, 4 references
- [3] doi:10.1038/s41598-023-41326-8 [code]
- Signature methods for brain-computer interfaces.Journal: Scientific reportsIn common: pyRiemann, MNE-Python, scikit-learn, 1 other tool, bbci.de/competition/iv, methods / tools, EEG, 1 reference
- [4] doi:10.3390/s22155771 [code]
- Subject-Dependent Artifact Removal for Enhancing Motor Imagery Classifier Performance under Poor Skills.Journal: Sensors (Basel, Switzerland)In common: MNE-Python, scikit-learn, pandas, 3 other tools, bbci.de/competition/iv, methods / tools, EEG, 1 reference
- [5] doi:10.1038/s41598-025-16219-7 [code]
- Temporal convolutional transformer for EEG based motor imagery decoding.Journal: Scientific reportsIn common: MNE-Python, scikit-learn, pandas, 3 other tools, bbci.de/competition/iv, EEG, 1 reference
- [6] doi:10.1162/imag_a_00511 [code]
- Deep Riemannian Networks for end-to-end EEG decoding.Journal: Imaging neuroscience (Cambridge, Mass.)In common: pyRiemann, scikit-learn, pandas, 2 other tools, EEG, 3 references
- [7] doi:10.3390/s25072259
- EEG Signal Prediction for Motor Imagery Classification in Brain-Computer Interfaces.Journal: Sensors (Basel, Switzerland)In common: bbci.de/competition/iv, EEG, 4 references
- [8] doi:10.3389/fninf.2024.1459970 [code]
- hvEEGNet: a novel deep learning model for high-fidelity EEG reconstruction.Journal: Frontiers in neuroinformaticsIn common: MNE-Python, scikit-learn, pandas, 3 other tools, bbci.de/competition/iv, EEG, 1 reference
- [9] doi:10.3389/fnhum.2026.1895016 [code]
- A confidence-gated source selection strategy for cross-session transfer in brain-computer interfaces.Journal: Frontiers in human neuroscienceIn common: pyRiemann, MNE-Python, scikit-learn, 2 other tools, methods / tools, EEG, 2 references
- [10] doi:10.1038/s41598-025-06364-4 [code]
- Advancing BCI with a transformer-based model for motor imagery classification.Journal: Scientific reportsIn common: scikit-learn, SciPy, NumPy, bbci.de/competition/iv, methods / tools, EEG, 2 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 4 repositories of the authors' code, each at its verified commit and with its license, 3 scripts, and 1 match between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:7d023112233fdb45…
Add the badge to the code's README
If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.
Markdown
<!-- oscr-badge:start -->
[](https://openscicode.org/badge/doi/10.1186/s40708-026-00295-0)
<!-- oscr-badge:end -->reStructuredText
.. oscr-badge:start
.. image:: https://openscicode.org/badge/doi/10.1186/s40708-026-00295-0.svg
:target: https://openscicode.org/badge/doi/10.1186/s40708-026-00295-0
:alt: OSCR
.. oscr-badge:endHTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1186/s40708-026-00295-0"><img src="https://openscicode.org/badge/doi/10.1186/s40708-026-00295-0.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".
- souissijihen/BCI_RW_FBCSP_GigaDB on GitHub (add a README there)
- souissijihen/bci_rw_fbcsp- on GitHub (add a README there)
If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.
Report a mismatch between the code and the paper · Report a code error (signed in)
Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.
Report a reproduction failure (signed in)
Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
