def align(trials, window, offsets): sample_rate = utils.get_samplerate(trials) w = np.arange(int(window[0]*sample_rate), int(sample_rate)) feat_lab = [ trials.feat_lab[0], (w / float(sample_rate)).tolist()] feat_shape = (trials.feat_shape[0], len(w)) data = np.zeros(feat_shape + (trials.ninstances,)) for i,t in enumerate(offsets): t -= window[0] data[:,:,i] = trials.data[:,int(t*sample_rate)+w,i] trials_aligned = DataSet(data=data, feat_lab=feat_lab, default=trials) return trials_aligned
def slice(d, markers_to_class, offsets): ''' Slice function, used to extract fixed-length segments (called trials) of EEG from a recording. Opposite of :func:`psychic.concatenate_trials`. Segments are sliced based on the onset of some event code. Given for example an EEG recording which contains two marker codes: 1. Left finger tapping 2. Right finger tapping Trials can be extracted in the following manner: >>> import psychic >>> d = psychic.load_bdf(psychic.find_data_path('priming-short.bdf')) >>> mdict = {1:'related', 2:'unrelated'} >>> sample_rate = psychic.get_samplerate(d) >>> begin = int(-0.2 * sample_rate) >>> end = int(1.0 * sample_rate) >>> trials = psychic.slice(d, mdict, (begin, end)) >>> print trials DataSet with 208 instances, 12280 features [40x307], 2 classes: [104, 104], extras: [] Parameters ---------- markers_to_class : dict A dictionary containing as keys the event codes to use as onset of the trial and as values a class label for the resulting trials. For example ``{1:'left finger tapping', 2:'right finger tapping'}`` offsets : tuple Indicates the time (start, end), relative to the onset of marker, to extract as trial. Values are given in samples. Returns ------- d : :class:`DataSet` The extracted segments: - ``d.data``: [channels x samples x trials] - ``d.labels``: [classes x trials] - ``d.ids``: Timestamps indicating the marker onsets - ``d.cl_lab``: The class labels as specified in the ``markers_to_class`` dictionary - ``d.feat_lab``: Feature labels for the axes [channels (strings), time in seconds (floats)] ''' assert len(d.feat_shape) == 1, 'Data must be continuous EEG.' assert d.labels.shape[0] == 1 and d.labels.dtype == np.int, ('Labels are' 'the wrong format. It must be an integer marker stream.') start_off, end_off = offsets data, labels, ids = [], [], [] cl_lab = sorted(set(markers_to_class.values())) events, events_i, events_d = markers.markers_to_events(d.labels.flat) for (mark, cl) in markers_to_class.items(): cl_i = cl_lab.index(cl) for i in events_i[events==mark]: # fails if there is *ONE* event (start, end) = i + start_off, i + end_off if start < 0 or end > d.ninstances: logging.getLogger('psychic.utils.slice').warning( 'Cannot extract slice [%d, %d] for class %s' % (start, end, cl)) continue dslice = d[start:end] data.append(dslice.data) labels.append(cl_i) ids.append(d.ids[:,i]) event_time = np.arange(start_off, end_off) / float(utils.get_samplerate(d)) feat_lab = [d.feat_lab[0], event_time.tolist()] if len(data) == 0: data = np.zeros(d.feat_shape + (len(event_time),0)) labels = np.zeros((len(cl_lab),0)) ids = np.zeros((1,0)) else: data = np.concatenate([x[...,np.newaxis] for x in data], axis=2) labels = helpers.to_one_of_n(labels, class_rows=range(len(cl_lab))) ids = np.atleast_2d(np.vstack(ids).T) feat_dim_lab = ['channels', 'time'] d = DataSet( data=data, labels=labels, ids=ids, cl_lab=cl_lab, feat_lab=feat_lab, feat_dim_lab=feat_dim_lab, default=d ) return d.sorted()