def _create_cnt_y_and_trial_bounds_from_start_and_ival(n_samples, events, fs, name_to_start_codes, epoch_ival_ms): ival_in_samples = ms_to_samples(np.array(epoch_ival_ms), fs) start_offset = np.int32(np.round(ival_in_samples[0])) # we will use ceil but exclusive... stop_offset = np.int32(np.ceil(ival_in_samples[1])) mrk_code_to_name_and_y = _to_mrk_code_to_name_and_y(name_to_start_codes) class_to_n_trials = Counter() n_classes = len(name_to_start_codes) cnt_y = np.zeros((n_samples, n_classes), dtype=np.int64) i_start_stops = [] for i_sample, mrk_code in zip(events[:, 0], events[:, 1]): start_sample = int(i_sample) + start_offset stop_sample = int(i_sample) + stop_offset if mrk_code in mrk_code_to_name_and_y: if start_sample < 0: log.warning( "Ignore trial with marker code {:d}, would start at " "sample {:d}".format(mrk_code, start_sample)) continue if stop_sample > n_samples: log.warning("Ignore trial with marker code {:d}, would end at " "sample {:d} of {:d}".format( mrk_code, stop_sample - 1, n_samples - 1)) continue name, this_y = mrk_code_to_name_and_y[mrk_code] i_start_stops.append((start_sample, stop_sample)) cnt_y[start_sample:stop_sample, this_y] = 1 class_to_n_trials[name] += 1 log.info("Trial per class:\n{:s}".format(str(class_to_n_trials))) return cnt_y, i_start_stops
def _create_signal_target_from_start_and_ival(data, events, fs, name_to_codes, epoch_ival_ms): ival_in_samples = ms_to_samples(np.array(epoch_ival_ms), fs) start_offset = np.int32(np.round(ival_in_samples[0])) # we will use ceil but exclusive... stop_offset = np.int32(np.ceil(ival_in_samples[1])) mrk_code_to_name_and_y = _to_mrk_code_to_name_and_y(name_to_codes) class_to_n_trials = Counter() X = [] y = [] for i_sample, mrk_code in zip(events[:, 0], events[:, 1]): start_sample = int(i_sample) + start_offset stop_sample = int(i_sample) + stop_offset if mrk_code in mrk_code_to_name_and_y: name, this_y = mrk_code_to_name_and_y[mrk_code] X.append(data[:, start_sample:stop_sample].astype(np.float32)) y.append(np.int64(this_y)) class_to_n_trials[name] += 1 log.info("Trial per class:\n{:s}".format(str(class_to_n_trials))) return SignalAndTarget(np.array(X), np.array(y))
def add_breaks(events, fs, break_start_code, break_stop_code, name_to_start_codes, name_to_stop_codes, min_break_length_ms=None, max_break_length_ms=None, break_start_offset_ms=None, break_stop_offset_ms=None): """ Add break events to given events. Parameters ---------- events: 2d-array Dimensions: Number of events, 2. For each event, should contain sample index and marker code. fs: number Sampling rate. break_start_code: int Marker code that will be used for break start markers. break_stop_code: int Marker code that will be used for break stop markers. name_to_start_codes: OrderedDict (str -> int or list of int) Ordered dictionary mapping class names to start marker code or start marker codes. name_to_stop_codes: dict (str -> int or list of int), optional Dictionary mapping class names to stop marker code or stop marker codes. min_break_length_ms: number, optional Minimum length in milliseconds a break should have to be included. max_break_length_ms: number, optional Maximum length in milliseconds a break can have to be included. break_start_offset_ms: number, optional What offset from trial end to start of the break in ms. break_stop_offset_ms: number, optional What offset from next trial start end to previous break end in ms. Returns ------- events: 2d-array Events with break start and stop markers. """ min_samples = (None if min_break_length_ms is None else ms_to_samples( min_break_length_ms, fs)) max_samples = (None if max_break_length_ms is None else ms_to_samples( max_break_length_ms, fs)) orig_events = events break_starts, break_stops = _extract_break_start_stop_ms( events, name_to_start_codes, name_to_stop_codes) break_durations = break_stops - break_starts valid_mask = np.array([True] * len(break_starts)) if min_samples is not None: valid_mask[break_durations < min_samples] = False if max_samples is not None: valid_mask[break_durations > max_samples] = False if sum(valid_mask) == 0: return deepcopy(events) break_starts = break_starts[valid_mask] break_stops = break_stops[valid_mask] if break_start_offset_ms is not None: break_starts += int(round(ms_to_samples(break_start_offset_ms, fs))) if break_stop_offset_ms is not None: break_stops += int(round(ms_to_samples(break_stop_offset_ms, fs))) break_events = np.zeros((len(break_starts) * 2, 2)) break_events[0::2, 0] = break_starts break_events[1::2, 0] = break_stops break_events[0::2, 1] = break_start_code break_events[1::2, 1] = break_stop_code new_events = np.concatenate((orig_events, break_events)) # sort events sort_order = np.argsort(new_events[:, 0], kind='mergesort') new_events = new_events[sort_order] return new_events
def _create_cnt_y_and_trial_bounds_from_start_stop(n_samples, events, fs, name_to_start_codes, epoch_ival_ms, name_to_stop_codes): """ Create a one-hot-encoded continuous marker array (cnt_y). Parameters ---------- n_samples: int Number of samples=timesteps in the recorded data. events: 2d-array Dimensions: Number of events, 2. For each event, should contain sample index and marker code. fs: number Sampling rate. name_to_start_codes: OrderedDict (str -> int or list of int) Ordered dictionary mapping class names to marker code or marker codes. y-labels will be assigned in increasing key order, i.e. first classname gets y-value 0, second classname y-value 1, etc. epoch_ival_ms: iterable of (int,int) Epoching interval in milliseconds. In case only `name_to_codes` given, represents start offset and stop offset from start markers. In case `name_to_stop_codes` given, represents offset from start marker and offset from stop marker. E.g. [500, -500] would mean 500ms after the start marker until 500 ms before the stop marker. name_to_stop_codes: dict (str -> int or list of int), optional Dictionary mapping class names to stop marker code or stop marker codes. Order does not matter, dictionary should contain each class in `name_to_codes` dictionary. Returns ------- cnt_y: 2d-array Timeseries of one-hot-labels, time x classes. trial_bounds: list of (int,int) List of (trial_start, trial_stop) tuples. """ assert np.array_equal(list(name_to_start_codes.keys()), list(name_to_stop_codes.keys())) events = np.asarray(events) ival_in_samples = ms_to_samples(np.array(epoch_ival_ms), fs) start_offset = np.int32(np.round(ival_in_samples[0])) # we will use ceil but exclusive... stop_offset = np.int32(np.ceil(ival_in_samples[1])) start_code_to_name_and_y = _to_mrk_code_to_name_and_y(name_to_start_codes) # Ensure all stop marker codes are iterables for name in name_to_stop_codes: codes = name_to_stop_codes[name] if not hasattr(codes, '__len__'): name_to_stop_codes[name] = [codes] all_stop_codes = np.concatenate(list(name_to_stop_codes.values())).astype( np.int64) class_to_n_trials = Counter() n_classes = len(name_to_start_codes) cnt_y = np.zeros((n_samples, n_classes), dtype=np.int64) event_samples = events[:, 0] event_codes = events[:, 1] i_start_stops = [] i_event = 0 first_start_code_found = False while i_event < len(events): while i_event < len(events) and (event_codes[i_event] not in start_code_to_name_and_y): i_event += 1 if i_event < len(events): start_sample = event_samples[i_event] start_code = event_codes[i_event] start_name = start_code_to_name_and_y[start_code][0] start_y = start_code_to_name_and_y[start_code][1] i_event += 1 first_start_code_found = True waiting_for_end_code = True while i_event < len(events) and (event_codes[i_event] not in all_stop_codes): if event_codes[i_event] in start_code_to_name_and_y: log.warning( "New start marker {:.0f} at {:.0f} samples found, " "no end marker for earlier start marker {:.0f} " "at {:.0f} samples found.".format( event_codes[i_event], event_samples[i_event], start_code, start_sample)) start_sample = event_samples[i_event] start_name = start_code_to_name_and_y[start_code][0] start_code = event_codes[i_event] start_y = start_code_to_name_and_y[start_code][1] i_event += 1 if i_event == len(events): if waiting_for_end_code: log.warning( ("No end marker for start marker code {:.0f} " "at sample {:.0f} found.").format(start_code, start_sample)) elif (not first_start_code_found): log.warning("No markers found at all.") break stop_sample = event_samples[i_event] stop_code = event_codes[i_event] assert stop_code in name_to_stop_codes[start_name] i_start = int(start_sample) + start_offset i_stop = int(stop_sample) + stop_offset cnt_y[i_start:i_stop, start_y] = 1 i_start_stops.append((i_start, i_stop)) class_to_n_trials[start_name] += 1 waiting_for_end_code = False log.info("Trial per class:\n{:s}".format(str(class_to_n_trials))) return cnt_y, i_start_stops
def _create_signal_target_from_start_and_stop(data, events, fs, name_to_start_codes, epoch_ival_ms, name_to_stop_codes): assert np.array_equal(list(name_to_start_codes.keys()), list(name_to_stop_codes.keys())) ival_in_samples = ms_to_samples(np.array(epoch_ival_ms), fs) start_offset = np.int32(np.round(ival_in_samples[0])) # we will use ceil but exclusive... stop_offset = np.int32(np.ceil(ival_in_samples[1])) start_code_to_name_and_y = _to_mrk_code_to_name_and_y(name_to_start_codes) # Ensure all stop marker codes are iterables for name in name_to_stop_codes: codes = name_to_stop_codes[name] if not hasattr(codes, '__len__'): name_to_stop_codes[name] = [codes] all_stop_codes = np.concatenate(list(name_to_stop_codes.values())) class_to_n_trials = Counter() X = [] y = [] event_samples = events[:, 0] event_codes = events[:, 1] i_event = 0 while i_event < len(events): while i_event < len(events) and (event_codes[i_event] not in start_code_to_name_and_y): i_event += 1 if i_event < len(events): start_sample = event_samples[i_event] start_code = event_codes[i_event] start_name = start_code_to_name_and_y[start_code][0] start_y = start_code_to_name_and_y[start_code][1] i_event += 1 while i_event < len(events) and (event_codes[i_event] not in all_stop_codes): if event_codes[i_event] in start_code_to_name_and_y: log.warning( "New start marker {:.0f} at {:.0f} samples found, " "no end marker for earlier start marker {:.0f} " "at {:.0f} samples found.".format( event_codes[i_event], event_samples[i_event], start_code, start_sample)) start_sample = event_samples[i_event] start_name = start_code_to_name_and_y[start_code][0] start_code = event_codes[i_event] start_y = start_code_to_name_and_y[start_code][1] i_event += 1 if i_event == len(events): log.warning( ("No end marker for start marker code {:.0f} " "at sample {:.0f} found.").format(start_code, start_sample)) break stop_sample = event_samples[i_event] stop_code = event_codes[i_event] assert stop_code in name_to_stop_codes[start_name] i_start = int(start_sample) + start_offset i_stop = int(stop_sample) + stop_offset X.append(data[:, i_start:i_stop].astype(np.float32)) y.append(np.int64(start_y)) class_to_n_trials[start_name] += 1 log.info("Trial per class:\n{:s}".format(str(class_to_n_trials))) return SignalAndTarget(X, np.array(y))