Skip to content

Commit

Permalink
- issue #5 :
Browse files Browse the repository at this point in the history
	- auto lint with autopep8
- issue #3 :
	- Added visualization module:
		- Learning curve: train_val
		- ROC curve
		- Confustion Matrix

 On branch dev
 Changes to be committed:
	modified:   aawedha/analysis/preprocess.py
	modified:   aawedha/evaluation/base.py
	modified:   aawedha/evaluation/cross_subject.py
	modified:   aawedha/evaluation/single_subject.py
	modified:   aawedha/io/base.py
	modified:   aawedha/io/bci_comp_iv_2a.py
	modified:   aawedha/io/exoskeleton.py
	modified:   aawedha/io/freiburg_online.py
	modified:   aawedha/io/inria_ern.py
	modified:   aawedha/io/laresi.py
	modified:   aawedha/io/physionet_mi.py
	modified:   aawedha/io/san_diego.py
	modified:   aawedha/io/tsinghua.py
	modified:   aawedha/models/EEGModels.py
	modified:   aawedha/paradigms/base.py
	modified:   aawedha/paradigms/erp.py
	modified:   aawedha/paradigms/hybrid.py
	modified:   aawedha/paradigms/motor_imagery.py
	modified:   aawedha/paradigms/ssvep.py
	modified:   aawedha/paradigms/subject.py
	modified:   aawedha/process/base.py
	modified:   aawedha/scripts/cross_subj.py
	modified:   aawedha/scripts/single_subj.py
	new file:   aawedha/visualization/__init__.py
	new file:   aawedha/visualization/viz.py
  • Loading branch information
okbalefthanded committed Nov 29, 2019
1 parent e9c55f7 commit d79a199
Show file tree
Hide file tree
Showing 25 changed files with 1,088 additions and 987 deletions.
21 changes: 12 additions & 9 deletions aawedha/analysis/preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,27 @@


def bandpass(eeg, band, fs, order=2):
B,A = sig.butter(order, np.array(band)/(fs/2), btype='bandpass')
return sig.filtfilt(B, A, eeg, axis=0)
B, A = sig.butter(order, np.array(band) / (fs / 2), btype='bandpass')
return sig.filtfilt(B, A, eeg, axis=0)


def eeg_epoch(eeg, epoch_length, markers):
'''
input
input
: eeg : continuous eeg : 2D numpy array samples x channels
: epoch_length : 1D numpy array (size 2 )epoch start and stop in samples
: epoch_length : 1D numpy array (size 2 )epoch start and stop
in samples
: markers : event markers onset in samples 1D array 1,n_markers
output
output
: eeg_epochs : 3D array of epoched EEG : samples x channels x trials (Fortran ordering aka MATLAB format)
'''
channels = int(eeg.shape[1])
epoch_length = np.around(epoch_length)
dur = np.arange(epoch_length[0], epoch_length[1]).reshape((np.diff(epoch_length)[0],1)) * np.ones( (1, len(markers)),dtype=int)
dur = np.arange(epoch_length[0], epoch_length[1]).reshape(
(np.diff(epoch_length)[0], 1)) * np.ones((1, len(markers)), dtype=int)
samples = len(dur)
epoch_idx = dur + markers
eeg_epochs = np.array(eeg[epoch_idx,:]).reshape((samples, len(markers), channels), order='F').transpose((0,2,1))
return eeg_epochs
eeg_epochs = np.array(eeg[epoch_idx, :]).reshape(
(samples, len(markers), channels), order='F').transpose((0, 2, 1))
return eeg_epochs
122 changes: 58 additions & 64 deletions aawedha/evaluation/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,61 +9,57 @@
import abc
import os


class Evaluation(object):

def __init__(self, n_subjects=0, partition=[],
folds=[], dataset=None,
model=None, verbose=2
):

def __init__(self, n_subjects=0, partition=[], folds=[], dataset=None,
model=None, verbose=2):
'''
'''
self.n_subjects = n_subjects
self.partition = partition
self.folds = folds
self.dataset = dataset
self.model = model
self.cm = [] # confusion matrix per fold
self.results = {} # dict
self.cm = [] # confusion matrix per fold
self.results = {} # dict
self.model_history = {}
self.verbose = verbose


@abc.abstractmethod
def generate_split(self, nfolds):
'''
'''
pass

@abc.abstractmethod
@abc.abstractmethod
def run_evaluation(self):
'''
'''
pass


def measure_performance(self, Y_test, probs):
'''
'''
preds = probs.argmax(axis=-1)
y_true = Y_test.argmax(axis=-1)
y_true = Y_test.argmax(axis=-1)
classes = Y_test.shape[1]
acc = np.mean(preds == y_true)
acc = np.mean(preds == y_true)

self.cm.append(confusion_matrix(Y_test.argmax(axis=-1), preds))

if classes == 2:
fp_rate, tp_rate, thresholds = roc_curve(y_true, probs[:,1])
auc_score = auc(fp_rate, tp_rate)
if classes == 2:
fp_rate, tp_rate, thresholds = roc_curve(y_true, probs[:, 1])
auc_score = auc(fp_rate, tp_rate)
return acc.item(), auc_score.item(), fp_rate, tp_rate
else:
return acc.item()



def results_reports(self, res, tfpr={}):
'''
'''
results = {}
#
if tfpr:
# res : (metric, subjects, folds)
# means = res.mean(axis=-1) # mean across folds
Expand All @@ -72,105 +68,104 @@ def results_reports(self, res, tfpr={}):
results['acc_mean_per_fold'] = r1.mean(axis=0)
results['acc_mean_per_subj'] = r1.mean(axis=1)
results['acc_mean'] = r1.mean()

#
r2 = np.array(res['auc'])
results['auc'] = r2
results['auc_mean_per_fold'] = r2.mean(axis=0)
results['auc_mean_per_subj'] = r2.mean(axis=1)
results['auc_mean'] = r2.mean()

#
results['fpr'] = tfpr['fp']
results['tpr'] = tfpr['tp']
else:
# res : (subjects, folds)
results['acc'] = res
results['acc_mean_per_fold'] = res.mean(axis=0) # mean across folds
results['acc_mean_per_subject'] = res.mean(axis=1) # mean across subjects and folds
# mean across folds
results['acc_mean_per_fold'] = res.mean(axis=0)
# mean across subjects and folds
results['acc_mean_per_subject'] = res.mean(axis=1)
results['acc_mean'] = res.mean()

return results
return results

def get_folds(self, nfolds, population, tr, vl, ts, exclude_subj=True):
'''
'''
folds = []
if hasattr(self.dataset, 'test_epochs'):
if hasattr(self.dataset, 'test_epochs'):
if self.__class__.__name__ == 'CrossSubject':
# independent test set
# list : nfolds : [nsubjects_train] [nsubjects_val]
# list : nfolds : [nsubjects_train] [nsubjects_val]
for subj in range(self.n_subjects):
selection = np.arange(0, self.n_subjects)
if exclude_subj:
# fully cross-subject, no subject train data in fold
selection = np.delete(selection, subj)
for fold in range(nfolds):
np.random.shuffle(selection)
folds.append([np.array(selection[:tr]), np.array(selection[tr:])])
for fold in range(nfolds):
np.random.shuffle(selection)
folds.append([np.array(selection[:tr]),
np.array(selection[tr:])])
elif self.__class__.__name__ == 'SingleSubject':
# generate folds for test set from one set
# generate folds for test set from one set
pop = population
t = tr
v = vl
s = ts
s = ts
for f in range(nfolds):
if type(population) is np.ndarray:
# inconsistent numbers of trials among subjects
if isinstance(population, np.ndarray):
# inconsistent numbers of trials among subjects
sbj = []
for subj in range(self.n_subjects):
for subj in range(self.n_subjects):
pop = population[subj]
t = tr[subj]
v = vl[subj]
s = ts[subj]
tmp = np.array(random.sample(range(pop), pop))
sbj.append([tmp[:t], tmp[t:t+v], tmp[-s:]])
tmp = np.array(random.sample(range(pop), pop))
sbj.append([tmp[:t], tmp[t:t + v], tmp[-s:]])
folds.append(sbj)
else:
# same numbers of trials for all subjects
else:
# same numbers of trials for all subjects
tmp = np.array(random.sample(range(pop), pop))
folds.append([tmp[:t], tmp[t:t+v], tmp[-s:]])

#for _ in range(nfolds):
# tmp = np.array(random.sample(range(population), population))
# folds.append([tmp[:tr], tmp[tr:tr+vl], tmp[-ts:]])
folds.append([tmp[:t], tmp[t:t + v], tmp[-s:]])
else:
# generate folds for test set from one set
for _ in range(nfolds):
tmp = np.array(random.sample(range(population), population))
folds.append([tmp[:tr], tmp[tr:tr+vl], tmp[-ts:]])

return folds
folds.append([tmp[:tr], tmp[tr:tr + vl], tmp[-ts:]])
#
return folds

def fit_scale(self, X):
mu = X.mean(axis=0)
sigma = X.std(axis=0)
X = np.subtract(X, mu[None,:,:])
X = np.divide(X, sigma[None,:,:])
X = np.subtract(X, mu[None, :, :])
X = np.divide(X, sigma[None, :, :])
return X, mu, sigma


def transform_scale(self, X, mu, sigma):
X = np.subtract(X, mu[None,:,:])
X = np.divide(X, sigma[None,:,:])
X = np.subtract(X, mu[None, :, :])
X = np.divide(X, sigma[None, :, :])
return X


def class_weights(self, y):
'''
'''
cl_weights = {}
classes = np.unique(y)
n_perclass = [np.sum(y==cl) for cl in classes]
n_perclass = [np.sum(y == cl) for cl in classes]
n_samples = np.sum(n_perclass)
ws = np.array([np.ceil(n_samples / cl).astype(int) for cl in n_perclass])
ws = np.array([np.ceil(n_samples / cl).astype(int)
for cl in n_perclass])
if np.unique(ws).size == 1:
# balanced classes
cl_weights = {cl:1 for cl in classes}
cl_weights = {cl: 1 for cl in classes}
else:
# unbalanced classes
if classes.size == 2:
cl_weights = {classes[ws == ws.max()].item():ws.max(), classes[ws < ws.max()].item():1}
cl_weights = {classes[ws == ws.max()].item(
): ws.max(), classes[ws < ws.max()].item(): 1}
else:
cl_weights = {cl:ws[idx] for idx,cl in enumerate(classes)}
cl_weights = {cl: ws[idx] for idx, cl in enumerate(classes)}
return cl_weights

def labels_to_categorical(self, y):
Expand All @@ -180,18 +175,17 @@ def labels_to_categorical(self, y):
if np.isin(0, classes):
y = to_categorical(y)
else:
y = to_categorical(y-1)
y = to_categorical(y - 1)
return y

def save_model(self, folderpath=None):
'''
'''
if not os.path.isdir('trained'):
os.mkdir('trained')
if not folderpath:
folderpath = 'trained'
if not folderpath:
folderpath = 'trained'
prdg = self.dataset.paradigm.title
dt = self.dataset.title
filepath = folderpath + '/' + '_'.join(['model',prdg,dt,'.h5'])
filepath = folderpath + '/' + '_'.join(['model', prdg, dt, '.h5'])
self.model.save(filepath)

Loading

0 comments on commit d79a199

Please sign in to comment.