braindecode 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 1.1
2
+ Name: Braindecode
3
+ Version: 0.1.0
4
+ Summary: A deep learning for raw time-domain EEG decoding toolbox.
5
+ Home-page: https://github.com/robintibor/braindecode
6
+ Author: Robin Tibor Schirrmeister
7
+ Author-email: robintibor@gmail.com
8
+ License: BSD 3-Clause
9
+ Description: Note: The old braindecode repository has been moved to https://github.com/robintibor/braindevel.
10
+
11
+ # Braindecode
12
+ A deep learning for raw time-domain EEG decoding toolbox.
13
+
14
+ Keywords: eeg deep-learning brain-state-decoding
15
+ Platform: UNKNOWN
16
+ Classifier: Development Status :: 3 - Alpha
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Intended Audience :: Science/Research
19
+ Classifier: Topic :: Software Development :: Build Tools
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: License :: OSI Approved :: BSD License
22
+ Classifier: Programming Language :: Python :: 2.7
23
+ Classifier: Programming Language :: Python :: 3.5
@@ -0,0 +1,11 @@
1
+ setup.py
2
+ Braindecode.egg-info/PKG-INFO
3
+ Braindecode.egg-info/SOURCES.txt
4
+ Braindecode.egg-info/dependency_links.txt
5
+ Braindecode.egg-info/requires.txt
6
+ Braindecode.egg-info/top_level.txt
7
+ braindecode/__init__.py
8
+ braindecode/iterators.py
9
+ braindecode/splitters.py
10
+ braindecode/trial_segment.py
11
+ braindecode/util.py
@@ -0,0 +1,2 @@
1
+ numpy
2
+ mne
@@ -0,0 +1 @@
1
+ braindecode
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 1.1
2
+ Name: Braindecode
3
+ Version: 0.1.0
4
+ Summary: A deep learning for raw time-domain EEG decoding toolbox.
5
+ Home-page: https://github.com/robintibor/braindecode
6
+ Author: Robin Tibor Schirrmeister
7
+ Author-email: robintibor@gmail.com
8
+ License: BSD 3-Clause
9
+ Description: Note: The old braindecode repository has been moved to https://github.com/robintibor/braindevel.
10
+
11
+ # Braindecode
12
+ A deep learning for raw time-domain EEG decoding toolbox.
13
+
14
+ Keywords: eeg deep-learning brain-state-decoding
15
+ Platform: UNKNOWN
16
+ Classifier: Development Status :: 3 - Alpha
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Intended Audience :: Science/Research
19
+ Classifier: Topic :: Software Development :: Build Tools
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: License :: OSI Approved :: BSD License
22
+ Classifier: Programming Language :: Python :: 2.7
23
+ Classifier: Programming Language :: Python :: 3.5
File without changes
@@ -0,0 +1,216 @@
1
+ import numpy as np
2
+ from numpy.random import RandomState
3
+
4
+
5
+ def get_balanced_batches(n_trials, rng, shuffle, n_batches=None,
6
+ batch_size=None):
7
+ """Create indices for batches balanced in size (batches will have maximum size difference of 1).
8
+ Supply either batch size or number of batches. Resulting batches
9
+ will not have the given batch size but rather the next largest batch size
10
+ that allows to split the set into balanced batches (maximum size difference 1).
11
+
12
+ Parameters
13
+ ----------
14
+ n_trials : int
15
+ Size of set.
16
+ rng :
17
+
18
+ shuffle :
19
+ Whether to shuffle indices before splitting set.
20
+ n_batches :
21
+ (Default value = None)
22
+ batch_size :
23
+ (Default value = None)
24
+
25
+ Returns
26
+ -------
27
+
28
+ """
29
+ assert batch_size is not None or n_batches is not None
30
+ if n_batches is None:
31
+ n_batches = int(np.round(n_trials / float(batch_size)))
32
+
33
+ if n_batches > 0:
34
+ min_batch_size = n_trials // n_batches
35
+ n_batches_with_extra_trial = n_trials % n_batches
36
+ else:
37
+ n_batches = 1
38
+ min_batch_size = n_trials
39
+ n_batches_with_extra_trial = 0
40
+ assert n_batches_with_extra_trial < n_batches
41
+ all_inds = np.array(range(n_trials))
42
+ if shuffle:
43
+ rng.shuffle(all_inds)
44
+ i_start_trial = 0
45
+ i_stop_trial = 0
46
+ batches = []
47
+ for i_batch in range(n_batches):
48
+ i_stop_trial += min_batch_size
49
+ if i_batch < n_batches_with_extra_trial:
50
+ i_stop_trial += 1
51
+ batch_inds = all_inds[range(i_start_trial, i_stop_trial)]
52
+ batches.append(batch_inds)
53
+ i_start_trial = i_stop_trial
54
+ assert i_start_trial == n_trials
55
+ return batches
56
+
57
+
58
+ class BalancedBatchSizeIterator(object):
59
+ """
60
+ Create batches of balanced size.
61
+
62
+ Parameters
63
+ ----------
64
+ batch_size: int
65
+ Resulting batches will not necessarily have the given batch size
66
+ but rather the next largest batch size that allows to split the set into
67
+ balanced batches (maximum size difference 1).
68
+ """
69
+ def __init__(self, batch_size):
70
+ self.batch_size = batch_size
71
+ self.rng = RandomState(328774)
72
+
73
+ def get_batches(self, dataset, shuffle):
74
+ n_trials = dataset.X.shape[0]
75
+ batches = get_balanced_batches(n_trials,
76
+ batch_size=self.batch_size,
77
+ rng=self.rng,
78
+ shuffle=shuffle)
79
+ for batch_inds in batches:
80
+ yield (dataset.X[batch_inds], dataset.y[batch_inds])
81
+
82
+ def reset_rng(self):
83
+ self.rng = RandomState(328774)
84
+
85
+
86
+ class CropsFromTrialsIterator(object):
87
+ def __init__(self, batch_size, input_time_length, n_preds_per_input,
88
+ check_preds_smaller_trial_len=True):
89
+ # TODO: remove this check preds smaller trila len and check that
90
+ # trials are smaller than input length
91
+ """
92
+
93
+ Parameters
94
+ ----------
95
+ batch_size: int
96
+ input_time_length: int
97
+ Input time length of the ConvNet, determines size of batches in
98
+ 3rd dimension.
99
+ n_preds_per_input: int
100
+ Number of predictions ConvNet makes per one input. Can be computed
101
+ by making a forward pass with the given input time length, the
102
+ output length in 3rd dimension is n_preds_per_input.
103
+ """
104
+ self.batch_size = batch_size
105
+ self.input_time_length = input_time_length
106
+ self.n_preds_per_input = n_preds_per_input
107
+ self.check_preds_smaller_trial_len = check_preds_smaller_trial_len
108
+ self.rng = RandomState((2017, 6, 28))
109
+
110
+ def reset_rng(self):
111
+ self.rng = RandomState((2017, 6, 28))
112
+
113
+ def get_batches(self, dataset, shuffle):
114
+ # start always at first predictable sample, so
115
+ # start at end of receptive field
116
+ n_receptive_field = self.input_time_length - self.n_preds_per_input + 1
117
+ i_trial_starts = [n_receptive_field - 1] * len(dataset.X)
118
+ i_trial_stops = [trial.shape[1] for trial in dataset.X]
119
+
120
+ if self.check_preds_smaller_trial_len:
121
+ check_trial_bounds(i_trial_starts, i_trial_stops,
122
+ self.n_preds_per_input)
123
+ start_stop_blocks_per_trial = compute_start_stop_block_inds(
124
+ i_trial_starts, i_trial_stops, self.input_time_length,
125
+ self.n_preds_per_input, self.check_preds_smaller_trial_len)
126
+ for i_trial, trial_blocks in enumerate(start_stop_blocks_per_trial):
127
+ assert trial_blocks[0][0] == 0
128
+ assert trial_blocks[-1][1] == i_trial_stops[i_trial]
129
+
130
+ return self.yield_block_batches(dataset.X, dataset.y,
131
+ start_stop_blocks_per_trial,
132
+ shuffle=shuffle)
133
+
134
+ def yield_block_batches(self, X, y, start_stop_blocks_per_trial, shuffle):
135
+ # add trial nr to start stop blocks and flatten at same time
136
+ i_trial_start_stop_block = [(i_trial, start, stop)
137
+ for i_trial, block in
138
+ enumerate(start_stop_blocks_per_trial)
139
+ for (start, stop) in block]
140
+ if shuffle:
141
+ self.rng.shuffle(i_trial_start_stop_block)
142
+
143
+ for i_block in range(0, len(i_trial_start_stop_block), self.batch_size):
144
+ i_block_stop = min(i_block + self.batch_size,
145
+ len(i_trial_start_stop_block))
146
+ start_stop_blocks = i_trial_start_stop_block[i_block:i_block_stop]
147
+ batch = create_batch_from_i_trial_start_stop_blocks(
148
+ X, y, start_stop_blocks, self.n_preds_per_input)
149
+ yield batch
150
+
151
+
152
+ def check_trial_bounds(i_trial_starts, i_trial_stops, n_preds_per_input):
153
+ for start, stop in zip(i_trial_starts, i_trial_stops):
154
+ assert stop - start >= n_preds_per_input, (
155
+ "Trial should be longer or equal than number of sample preds, "
156
+ "Trial length: {:d}, sample preds {:d}...".
157
+ format(stop - start, n_preds_per_input))
158
+
159
+
160
+ def compute_start_stop_block_inds(i_trial_starts, i_trial_stops,
161
+ input_time_length, n_preds_per_input,
162
+ check_preds_smaller_trial_len):
163
+ # create start stop indices for all batches still 2d trial -> start stop
164
+ start_stop_blocks_per_trial = []
165
+ for i_trial in range(len(i_trial_starts)):
166
+ trial_start = i_trial_starts[i_trial]
167
+ trial_stop = i_trial_stops[i_trial]
168
+ start_stop_blocks = get_start_stop_blocks_for_trial(
169
+ trial_start, trial_stop, input_time_length,
170
+ n_preds_per_input)
171
+
172
+ if check_preds_smaller_trial_len:
173
+ # check that block is correct, all predicted samples together
174
+ # should be the trial samples
175
+ all_predicted_samples = [
176
+ range(stop - n_preds_per_input,
177
+ stop) for _,stop in start_stop_blocks]
178
+ # this check takes about 50 ms in performance test
179
+ # whereas loop itself takes only 5 ms.. deactivate it if not necessary
180
+ assert np.array_equal(
181
+ range(i_trial_starts[i_trial], i_trial_stops[i_trial]),
182
+ np.unique(np.concatenate(all_predicted_samples)))
183
+
184
+ start_stop_blocks_per_trial.append(start_stop_blocks)
185
+ return start_stop_blocks_per_trial
186
+
187
+
188
+ def get_start_stop_blocks_for_trial(trial_start, trial_stop, input_time_length,
189
+ n_preds_per_input):
190
+ start_stop_blocks = []
191
+ i_window_stop = trial_start # now when we add sample preds in loop,
192
+ # first sample of trial corresponds to first prediction
193
+ while i_window_stop < trial_stop:
194
+ i_window_stop += n_preds_per_input
195
+ i_adjusted_stop = min(i_window_stop, trial_stop)
196
+ i_window_start = i_adjusted_stop - input_time_length
197
+ start_stop_blocks.append((i_window_start, i_adjusted_stop))
198
+
199
+ return start_stop_blocks
200
+
201
+
202
+ def create_batch_from_i_trial_start_stop_blocks(X, y, i_trial_start_stop_block,
203
+ n_preds_per_input):
204
+ Xs = []
205
+ ys = []
206
+ for i_trial, start, stop in i_trial_start_stop_block:
207
+ Xs.append(X[i_trial][:,start:stop])
208
+ # one-hot-encode targets
209
+ #block_y = np.zeros((n_classes, n_preds_per_input), dtype=np.float32)
210
+ #block_y[y[i_trial]] = 1
211
+ #block_y = np.ones((n_preds_per_input), dtype=np.int64) * y[i_trial]
212
+ #ys.append(block_y)
213
+ ys.append(y[i_trial])
214
+ batch_X = np.array(Xs)
215
+ batch_y = np.array(ys)
216
+ return batch_X, batch_y
@@ -0,0 +1,18 @@
1
+ import numpy as np
2
+
3
+ from braindecode.datasets.signal_target import apply_to_X_y
4
+
5
+
6
+ def concatenate_sets(set_a, set_b):
7
+ return apply_to_X_y(lambda a,b: np.concatenate((a,b), axis=0),
8
+ set_a, set_b)
9
+
10
+
11
+ def split_into_two_sets(dataset, first_set_fraction=None, n_boundary=None):
12
+ assert (first_set_fraction is None) != (n_boundary is None), (
13
+ "Supply either first_set_fraction or n_boundary")
14
+ if n_boundary is None:
15
+ n_boundary = int(round(len(dataset.X) * first_set_fraction))
16
+ first_set = apply_to_X_y(lambda a: a[:n_boundary], dataset)
17
+ second_set = apply_to_X_y(lambda a: a[n_boundary:], dataset)
18
+ return first_set, second_set
@@ -0,0 +1,198 @@
1
+ import logging
2
+ import numpy as np
3
+ import xarray as xr
4
+
5
+ log = logging.getLogger(__name__)
6
+
7
+
8
+ def create_target_series(cnt, marker_def, ival):
9
+ """
10
+ Compute one-hot encoded target series.
11
+ Parameters
12
+ ----------
13
+ cnt : DateArray
14
+ marker_def: OrderedDict (str -> list int)
15
+ Dictionary mapping class names -> list of marker codes. Order of keys
16
+ is used to determine indices of classes in one-hot encoded result.
17
+ ival : (number, number) tuple
18
+ Segmentation interval for each trial.
19
+ Returns
20
+ -------
21
+ 2darray
22
+ One-hot encoded target series.
23
+
24
+ """
25
+ assert 'fs' in cnt.attrs
26
+ assert 'events' in cnt.attrs
27
+ assert ival[0] < ival[1]
28
+ sample_ival = cnt.attrs['fs'] * np.array(ival) / 1000.0
29
+ sample_ival = np.int32(np.round(sample_ival))
30
+ assert sample_ival[0] < sample_ival[1]
31
+
32
+
33
+ class_names = marker_def.keys()
34
+ targets = np.zeros((len(cnt.data), len(class_names)), dtype=np.int32)
35
+ for i_sample, m in cnt.attrs['events']:
36
+ for class_idx, classname in enumerate(class_names):
37
+ if m in marker_def[classname]:
38
+ start_index = i_sample + sample_ival[0]
39
+ stop_index = i_sample + sample_ival[1]
40
+ assert stop_index > start_index
41
+ if start_index >= 0 and stop_index <= len(cnt.coords['time']):
42
+ targets[start_index:stop_index, class_idx] = 1
43
+ elif start_index < 0:
44
+ log.warn("Ignoring trial, start index < 0: {:d}".format(
45
+ start_index))
46
+ else:
47
+ assert stop_index > len(cnt.coords['time'])
48
+ log.warn("Ignoring trial, start index > n_samples:"
49
+ "{:d} > {:d} ".format(
50
+ stop_index, len(cnt.coords['time'])))
51
+ return targets
52
+
53
+
54
+ def compute_trial_start_stop_samples(y, check_trial_lengths_equal=True,
55
+ input_time_length=None):
56
+ """Computes trial start and end samples (end is inclusive) from
57
+ one-hot encoded y-matrix.
58
+ Specify input time length to kick out trials that are too short after
59
+ signal start.
60
+
61
+ Parameters
62
+ ----------
63
+ y : 2darray
64
+ check_trial_lengths_equal : bool
65
+ (Default value = True)
66
+ input_time_length : int, optional
67
+ (Default value = None)
68
+
69
+ Returns
70
+ -------
71
+
72
+ """
73
+ #TODO: change to start stop
74
+ trial_part = np.sum(y, 1) == 1
75
+ boundaries = np.diff(trial_part.astype(np.int32))
76
+ i_trial_starts = np.flatnonzero(boundaries == 1) + 1
77
+ i_trial_stops = np.flatnonzero(boundaries == -1) + 1
78
+ # it can happen that a trial is only partially there since the
79
+ # cnt signal was split in the middle of a trial
80
+ # for now just remove these
81
+ # use that start marker should always be before or equal to end marker
82
+ if i_trial_starts[0] >= i_trial_stops[0]:
83
+ # cut out first trial which only has end marker
84
+ i_trial_stops = i_trial_stops[1:]
85
+ if i_trial_starts[-1] >= i_trial_stops[-1]:
86
+ # cut out last trial which only has start marker
87
+ i_trial_starts = i_trial_starts[:-1]
88
+
89
+ assert (len(i_trial_starts) == len(i_trial_stops))
90
+ assert (np.all(i_trial_starts < i_trial_stops))
91
+ # possibly remove first trials if they are too early
92
+ if input_time_length is not None:
93
+ while i_trial_starts[0] < (input_time_length - 1):
94
+ i_trial_starts = i_trial_starts[1:]
95
+ i_trial_stops = i_trial_stops[1:]
96
+ if check_trial_lengths_equal:
97
+ # just checking that all trial lengths are equal
98
+ all_trial_lens = np.array(i_trial_stops) - np.array(i_trial_starts)
99
+ assert all(all_trial_lens == all_trial_lens[0]), (
100
+ "All trial lengths should be equal...")
101
+ return i_trial_starts, i_trial_stops
102
+
103
+
104
+ def segment_dat(cnt, marker_def, ival):
105
+ """Convert a continuous data object to an epoched one.
106
+
107
+ Given a continuous data object, a definition of classes, and an
108
+ interval, this method looks for markers as defined in ``marker_def``
109
+ and slices the dat according to the time interval given with
110
+ ``ival`` along the ``timeaxis``. The returned ``dat`` object stores
111
+ those slices and the class each slice belongs to.
112
+
113
+ Epochs that are too close to the borders and thus too short are
114
+ ignored.
115
+
116
+ If the segmentation does not result in any epochs (i.e. the markers
117
+ in ``marker_def`` could not be found in ``dat``, the resulting
118
+ epo.data will be an empty array.
119
+
120
+ This method is also suitable for **online processing**, please read
121
+ the documentation for the ``newsamples`` parameter and have a look
122
+ at the Examples below.
123
+
124
+ Parameters
125
+ ----------
126
+ dat : Data
127
+ the data object to be segmented
128
+ marker_def : dict
129
+ The keys are class names, the values are lists of markers
130
+ ival : [int, int]
131
+ The interval in milliseconds to cut around the markers. I.e. to
132
+ get the interval starting with the marker plus the remaining
133
+ 100ms define the interval like [0, 100]. The start point is
134
+ included, the endpoint is not (like: ``[start, end)``). To get
135
+ 200ms before the marker until 100ms after the marker do:
136
+ ``[-200, 100]`` Only negative or positive values are possible
137
+ (i.e. ``[-500, -100]``)
138
+
139
+ Returns
140
+ -------
141
+ epo : Data
142
+ a copy of the resulting epoched data.
143
+
144
+ Raises
145
+ ------
146
+ AssertionError
147
+ * if ``dat`` has not ``.fs`` or ``.markers`` attribute or if
148
+ ``ival[0] > ival[1]``.
149
+
150
+ Examples
151
+ --------
152
+
153
+ Offline Experiment
154
+
155
+ >>> # Define the markers belonging to class 1 and 2
156
+ >>> md = {'class 1': ['S1', 'S2'],
157
+ ... 'class 2': ['S3', 'S4']
158
+ ... }
159
+ >>> # Epoch the data -500ms and +700ms around the markers defined in
160
+ >>> # md
161
+ >>> epo = segment_dat(cnt, md, [-500, 700])
162
+
163
+ """
164
+
165
+ assert 'fs' in cnt.attrs
166
+ assert 'events' in cnt.attrs
167
+ y = create_target_series(cnt, marker_def, ival=ival)
168
+ # Create classes per trial
169
+ # and sample inds per trial from the target series
170
+ starts, stops = compute_trial_start_stop_samples(y)
171
+ classes = [np.argmax(y[i_s]) for i_s in starts]
172
+ sample_inds_per_trial = [list(range(i_start, i_stop))
173
+ for (i_start, i_stop) in zip(starts, stops)]
174
+
175
+ if len(sample_inds_per_trial) == 0:
176
+ assert "No epochs not tested yet"
177
+ data = np.array([])
178
+ else:
179
+ timeaxis = list(cnt.dims).index('time')
180
+ # np.take inserts a new dimension at `axis`...
181
+ data = cnt.data.take(sample_inds_per_trial, axis=timeaxis)
182
+ # we want that new dimension at axis 0 so we have to swap it.
183
+ # before that we have to convert the negative axis indices to
184
+ # their equivalent positive one, otherwise swapaxis will be one
185
+ # off.
186
+ data = data.swapaxes(0, timeaxis)
187
+ time = np.linspace(ival[0], ival[1],
188
+ data.shape[1], # assume timeaxis now on 1
189
+ endpoint=False)
190
+ epo = xr.DataArray(data,
191
+ coords={'trials': classes, 'time': time,
192
+ 'channels': cnt.channels,},
193
+ dims=('trials', 'time','channels',))
194
+ epo.attrs = cnt.attrs.copy()
195
+ # remove events part
196
+ epo.attrs.pop('events')
197
+ return epo
198
+
@@ -0,0 +1,156 @@
1
+ import os
2
+ import errno
3
+ import numpy as np
4
+ from copy import deepcopy
5
+
6
+
7
+ def deepcopy_xarr(xarr):
8
+ """
9
+ Deepcopy for xarray that makes sure coords and attrs
10
+ are properly deepcopied.
11
+ With normal copy method from xarray, when i mutated
12
+ xarr.coords[coord].data it would also mutate in the copy
13
+ and vice versa.
14
+ Parameters
15
+ ----------
16
+ xarr: DateArray
17
+
18
+ Returns
19
+ -------
20
+ xcopy: DateArray
21
+ Deep copy of xarr
22
+ """
23
+ xcopy = xarr.copy(deep=True)
24
+
25
+ for dim in xcopy.coords:
26
+ xcopy.coords[dim].data = np.copy(xcopy.coords[dim].data)
27
+ xcopy.attrs = deepcopy(xcopy.attrs)
28
+ for attr in xcopy.attrs:
29
+ xcopy.attrs[attr] = deepcopy(xcopy.attrs[attr])
30
+ return xcopy
31
+
32
+
33
+ class FuncAndArgs(object):
34
+ """Container for a function and its arguments.
35
+ Useful in case you want to pass a function and its arguments
36
+ to another function without creating a new class.
37
+ You can call the new instance either with the apply method or
38
+ the ()-call operator:
39
+
40
+ >>> FuncAndArgs(max, 2,3).apply(4)
41
+ 4
42
+ >>> FuncAndArgs(max, 2,3)(4)
43
+ 4
44
+ >>> FuncAndArgs(sum, [3,4])(8)
45
+ 15
46
+
47
+ """
48
+ def __init__(self, func, *args, **kwargs):
49
+ self.func = func
50
+ self.args = args
51
+ self.kwargs = kwargs
52
+
53
+
54
+ def apply(self, *other_args, **other_kwargs):
55
+ all_args = self.args + other_args
56
+ all_kwargs = self.kwargs.copy()
57
+ all_kwargs.update(other_kwargs)
58
+ return self.func(*all_args, **all_kwargs)
59
+
60
+ def __call__(self, *other_args, **other_kwargs):
61
+ return self.apply(*other_args, **other_kwargs)
62
+
63
+
64
+ class GetAttr(object):
65
+ """ Hacky class for yaml to return attr of something.
66
+ Uses new to actually return completely different object... """
67
+ def __new__(cls, obj, attr):
68
+ return getattr(obj, attr)
69
+
70
+ class ApplyFunc(object):
71
+ """ Hacky class to wrap function call in object for yaml loading... """
72
+ def __new__(cls, func,args, kwargs):
73
+ return func(*args, **kwargs)
74
+
75
+ def add_message_to_exception(exc, additional_message):
76
+ # give some more info...
77
+ # see http://www.ianbicking.org/blog/2007/09/re-raising-exceptions.html
78
+ args = exc.args
79
+ if not args:
80
+ arg0 = ''
81
+ else:
82
+
83
+ arg0 = args[0]
84
+ arg0 += additional_message
85
+ exc.args = (arg0, ) + args[1:]
86
+
87
+ def unzip(l):
88
+ return zip(*l)
89
+
90
+ def dict_compare(d1, d2):
91
+ """From http://stackoverflow.com/a/18860653/1469195"""
92
+ d1_keys = set(d1.keys())
93
+ d2_keys = set(d2.keys())
94
+ intersect_keys = d1_keys.intersection(d2_keys)
95
+ added = d1_keys - d2_keys
96
+ removed = d2_keys - d1_keys
97
+ modified = {o : (d1[o], d2[o]) for o in intersect_keys if d1[o] != d2[o]}
98
+ same = set(o for o in intersect_keys if d1[o] == d2[o])
99
+ return added, removed, modified, same
100
+
101
+ def dict_equal(d1,d2):
102
+ d1_keys = set(d1.keys())
103
+ d2_keys = set(d2.keys())
104
+ intersect_keys = d1_keys.intersection(d2_keys)
105
+ modified = {o : (d1[o], d2[o]) for o in intersect_keys if d1[o] != d2[o]}
106
+ return (intersect_keys == d2_keys and intersect_keys == d1_keys and
107
+ len(modified) == 0)
108
+
109
+ def dict_is_subset(d1,d2):
110
+ added, removed, modified, same = dict_compare(d1, d2)
111
+ return (len(added) == 0 and len(modified) == 0)
112
+
113
+ def merge_dicts(*dict_args):
114
+ '''
115
+ Given any number of dicts, shallow copy and merge into a new dict,
116
+ precedence goes to key value pairs in latter dicts.
117
+ http://stackoverflow.com/a/26853961
118
+ '''
119
+ result = {}
120
+ for dictionary in dict_args:
121
+ result.update(dictionary)
122
+ return result
123
+
124
+ def touch_file(path):
125
+ # from http://stackoverflow.com/a/12654798/1469195
126
+ basedir = os.path.dirname(path)
127
+ if not os.path.exists(basedir):
128
+ os.makedirs(basedir)
129
+ with open(path, 'a'):
130
+ os.utime(path, None)
131
+
132
+
133
+ def to_tuple(sequence_or_element, length=None):
134
+ if hasattr(sequence_or_element, '__len__'):
135
+ assert length is None
136
+ return tuple(sequence_or_element)
137
+ else:
138
+ if length is None:
139
+ return (sequence_or_element, )
140
+ else:
141
+ return (sequence_or_element,) * length
142
+
143
+
144
+ def mkdir_p(path):
145
+ try:
146
+ os.makedirs(path)
147
+ except OSError as exc: # Python >2.5
148
+ if exc.errno == errno.EEXIST and os.path.isdir(path):
149
+ pass
150
+ else:
151
+ raise
152
+
153
+ def select_inverse_inds(arr, inds):
154
+ mask = np.ones(len(arr),dtype=bool)
155
+ mask[inds] = False
156
+ return arr[mask]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,62 @@
1
+ from setuptools import setup, find_packages # Always prefer setuptools over distutils
2
+ from codecs import open # To use a consistent encoding
3
+ from os import path
4
+
5
+ here = path.abspath(path.dirname(__file__))
6
+
7
+ # README.md is used as the long description by default
8
+ # Get the long description from the relevant file
9
+ with open(path.join(here, 'README.md'), encoding='utf-8') as f:
10
+ long_description = f.read()
11
+
12
+
13
+ setup(
14
+ name='Braindecode',
15
+
16
+ # Versions should comply with PEP440. For a discussion on single-sourcing
17
+ # the version across setup.py and the project code, see
18
+ # http://packaging.python.org/en/latest/tutorial.html#version
19
+ version='0.1.0',
20
+
21
+ description='A deep learning for raw time-domain EEG decoding toolbox.',
22
+ long_description=long_description, #this is the
23
+
24
+ # The project's main homepage.
25
+ url='https://github.com/robintibor/braindecode',
26
+
27
+ # Author details
28
+ author='Robin Tibor Schirrmeister',
29
+ author_email='robintibor@gmail.com',
30
+
31
+ # Choose your license
32
+ license='BSD 3-Clause',
33
+
34
+ install_requires=['numpy','mne'],
35
+ #tests_require = [...]
36
+
37
+ # See https://PyPI.python.org/PyPI?%3Aaction=list_classifiers
38
+ classifiers=[
39
+ 'Development Status :: 3 - Alpha',
40
+
41
+ # Indicate who your project is intended for
42
+ "Intended Audience :: Developers",
43
+ "Intended Audience :: Science/Research",
44
+ 'Topic :: Software Development :: Build Tools',
45
+
46
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
47
+
48
+ # Pick your license as you wish (should match "license" above)
49
+ 'License :: OSI Approved :: BSD License',
50
+
51
+ # Specify the Python versions you support here. In particular, ensure
52
+ # that you indicate whether you support Python 2, Python 3 or both.
53
+ 'Programming Language :: Python :: 2.7',
54
+ 'Programming Language :: Python :: 3.5',
55
+ ],
56
+
57
+ # What does your project relate to?
58
+ keywords='eeg deep-learning brain-state-decoding',
59
+
60
+ packages=['braindecode'],
61
+
62
+ )