def test_strip_dev(version, want, have_unstripped, monkeypatch): """Test that stripping dev works.""" monkeypatch.setattr(mne.utils.check, 'import_module', lambda x: Bunch(__version__=version)) got_have_unstripped, same_version = check_version(version, want, strip=False, return_version=True) assert same_version == version assert got_have_unstripped is have_unstripped have, simpler_version = check_version( 'foo', want, return_version=True) # strip=True is the default assert have, (simpler_version, version) def looks_stable(version): try: [int(x) for x in version.split('.')] except ValueError: return False else: return True if looks_stable(version): assert 'dev' not in version assert 'rc' not in version assert simpler_version == version else: assert simpler_version != version assert 'dev' not in simpler_version assert 'rc' not in simpler_version assert not simpler_version.endswith('.') assert looks_stable(simpler_version)
def test_scaler(): """Test methods of Scaler.""" raw = io.read_raw_fif(raw_fname) events = read_events(event_name) picks = pick_types(raw.info, meg=True, stim=False, ecg=False, eog=False, exclude='bads') picks = picks[1:13:3] epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks, baseline=(None, 0), preload=True) epochs_data = epochs.get_data() y = epochs.events[:, -1] methods = (None, dict(mag=5, grad=10, eeg=20), 'mean', 'median') infos = (epochs.info, epochs.info, None, None) epochs_data_t = epochs_data.transpose([1, 0, 2]) for method, info in zip(methods, infos): if method == 'median' and not check_version('sklearn', '0.17'): assert_raises(ValueError, Scaler, info, method) continue if method == 'mean' and not check_version('sklearn', ''): assert_raises(ImportError, Scaler, info, method) continue scaler = Scaler(info, method) X = scaler.fit_transform(epochs_data, y) assert_equal(X.shape, epochs_data.shape) if method is None or isinstance(method, dict): sd = DEFAULTS['scalings'] if method is None else method stds = np.zeros(len(picks)) for key in ('mag', 'grad'): stds[pick_types(epochs.info, meg=key)] = 1. / sd[key] stds[pick_types(epochs.info, meg=False, eeg=True)] = 1. / sd['eeg'] means = np.zeros(len(epochs.ch_names)) elif method == 'mean': stds = np.array([np.std(ch_data) for ch_data in epochs_data_t]) means = np.array([np.mean(ch_data) for ch_data in epochs_data_t]) else: # median percs = np.array([np.percentile(ch_data, [25, 50, 75]) for ch_data in epochs_data_t]) stds = percs[:, 2] - percs[:, 0] means = percs[:, 1] assert_allclose(X * stds[:, np.newaxis] + means[:, np.newaxis], epochs_data, rtol=1e-12, atol=1e-20, err_msg=method) X2 = scaler.fit(epochs_data, y).transform(epochs_data) assert_array_equal(X, X2) # inverse_transform Xi = scaler.inverse_transform(X) assert_array_almost_equal(epochs_data, Xi) # Test init exception assert_raises(ValueError, Scaler, None, None) assert_raises(ValueError, scaler.fit, epochs, y) assert_raises(ValueError, scaler.transform, epochs) epochs_bad = Epochs(raw, events, event_id, 0, 0.01, picks=np.arange(len(raw.ch_names))) # non-data chs scaler = Scaler(epochs_bad.info, None) assert_raises(ValueError, scaler.fit, epochs_bad.get_data(), y)
def test_set(_bids_validate): """Test write_raw_bids conversion for EEGLAB data.""" # standalone .set file output_path = _TempDir() data_path = op.join(testing.data_path(), 'EEGLAB') # .set with associated .fdt output_path = _TempDir() data_path = op.join(testing.data_path(), 'EEGLAB') raw_fname = op.join(data_path, 'test_raw.set') raw = mne.io.read_raw_eeglab(raw_fname) # embedded - test mne-version assertion tmp_version = mne.__version__ mne.__version__ = '0.16' with pytest.raises(ValueError, match='Your version of MNE is too old.'): write_raw_bids(raw, bids_basename, output_path) mne.__version__ = tmp_version # proceed with the actual test for EEGLAB data write_raw_bids(raw, bids_basename, output_path, overwrite=False) read_raw_bids(bids_basename + '_eeg.set', output_path) with pytest.raises(TypeError, match="unexpected keyword argument 'foo'"): read_raw_bids(bids_basename + '_eeg.set', output_path, extra_params=dict(foo='bar')) with pytest.raises(FileExistsError, match="already exists"): # noqa: F821 write_raw_bids(raw, bids_basename, output_path=output_path, overwrite=False) _bids_validate(output_path) # check events.tsv is written # XXX: only from 0.18 onwards because events_from_annotations # is broken for earlier versions events_tsv_fname = op.join(output_path, 'sub-' + subject_id, 'ses-' + session_id, 'eeg', bids_basename + '_events.tsv') if check_version('mne', '0.18'): assert op.exists(events_tsv_fname) # Also cover iEEG # We use the same data and pretend that eeg channels are ecog raw.set_channel_types( {raw.ch_names[i]: 'ecog' for i in mne.pick_types(raw.info, eeg=True)}) output_path = _TempDir() write_raw_bids(raw, bids_basename, output_path) _bids_validate(output_path) # test anonymize and convert if check_version('mne', '0.20') and check_version('pybv', '0.2.0'): output_path = _test_anonymize(raw, bids_basename) _bids_validate(output_path)
def test_surface_source_morph_round_trip(smooth, lower, upper, n_warn, dtype): """Test round-trip morphing yields similar STCs.""" kwargs = dict(smooth=smooth, warn=True, subjects_dir=subjects_dir) stc = mne.read_source_estimate(fname_smorph) if dtype is complex: stc.data = 1j * stc.data assert_array_equal(stc.data.real, 0.) if smooth == 'nearest' and not check_version('scipy', '1.3'): with pytest.raises(ValueError, match='required to use nearest'): morph = compute_source_morph(stc, 'sample', 'fsaverage', **kwargs) return with pytest.warns(None) as w: morph = compute_source_morph(stc, 'sample', 'fsaverage', **kwargs) w = [ww for ww in w if 'vertices not included' in str(ww.message)] assert len(w) == n_warn assert morph.morph_mat.shape == (20484, len(stc.data)) stc_fs = morph.apply(stc) morph_back = compute_source_morph( stc_fs, 'fsaverage', 'sample', spacing=stc.vertices, **kwargs) assert morph_back.morph_mat.shape == (len(stc.data), 20484) stc_back = morph_back.apply(stc_fs) corr = np.corrcoef(stc.data.ravel(), stc_back.data.ravel())[0, 1] assert lower <= corr <= upper # check the round-trip power assert_power_preserved(stc, stc_back)
def test_plot_topomap_cnorm(): """Test colormap normalization.""" if check_version("matplotlib", "3.2.0"): from matplotlib.colors import TwoSlopeNorm else: from matplotlib.colors import DivergingNorm as TwoSlopeNorm np.random.seed(42) v = np.random.uniform(low=-1, high=2.5, size=64) v[:3] = [-1, 0, 2.5] montage = make_standard_montage("biosemi64") info = create_info(montage.ch_names, 256, "eeg").set_montage("biosemi64") cnorm = TwoSlopeNorm(vmin=-1, vcenter=0, vmax=2.5) # pass only cnorm, no vmin/vmax plot_topomap(v, info, cnorm=cnorm) # pass cnorm and vmin msg = "vmin=-1.* is implicitly defined by cnorm, ignoring vmin=-10.*" with pytest.warns(RuntimeWarning, match=msg): plot_topomap(v, info, vmin=-10, cnorm=cnorm) # pass cnorm and vmax msg = "vmax=2.5 is implicitly defined by cnorm, ignoring vmax=10.*" with pytest.warns(RuntimeWarning, match=msg): plot_topomap(v, info, vmax=10, cnorm=cnorm)
def test_plot_head_positions(): """Test plotting of head positions.""" import matplotlib.pyplot as plt info = read_info(evoked_fname) pos = np.random.RandomState(0).randn(4, 10) pos[:, 0] = np.arange(len(pos)) destination = (0., 0., 0.04) with warnings.catch_warnings(record=True): # old MPL will cause a warning plot_head_positions(pos) if check_version('matplotlib', '1.4'): plot_head_positions(pos, mode='field', info=info, destination=destination) else: assert_raises(RuntimeError, plot_head_positions, pos, mode='field', info=info, destination=destination) plot_head_positions([pos, pos]) # list support assert_raises(ValueError, plot_head_positions, ['pos']) assert_raises(ValueError, plot_head_positions, pos[:, :9]) assert_raises(ValueError, plot_head_positions, pos, 'foo') plt.close('all')
def test_plot_head_positions(): """Test plotting of head positions.""" info = read_info(evoked_fname) pos = np.random.RandomState(0).randn(4, 10) pos[:, 0] = np.arange(len(pos)) destination = (0., 0., 0.04) with pytest.warns(None): # old MPL will cause a warning plot_head_positions(pos) if check_version('matplotlib', '1.4'): plot_head_positions(pos, mode='field', info=info, destination=destination) else: pytest.raises(RuntimeError, plot_head_positions, pos, mode='field', info=info, destination=destination) plot_head_positions([pos, pos]) # list support pytest.raises(ValueError, plot_head_positions, ['pos']) pytest.raises(ValueError, plot_head_positions, pos[:, :9]) pytest.raises(ValueError, plot_head_positions, pos, 'foo') with pytest.raises(ValueError, match='shape'): with pytest.warns(None): # old mpl no viridis warning plot_head_positions(pos, axes=1.) plt.close('all')
def test_cache_dir(tmpdir, numba_conditional): """Test use of cache dir.""" tempdir = str(tmpdir) orig_dir = os.getenv('MNE_CACHE_DIR', None) orig_size = os.getenv('MNE_MEMMAP_MIN_SIZE', None) rng = np.random.RandomState(0) X = rng.randn(9, 2, 10) try: os.environ['MNE_MEMMAP_MIN_SIZE'] = '1K' os.environ['MNE_CACHE_DIR'] = tempdir # Fix error for #1507: in-place when memmapping with catch_logging() as log_file: permutation_cluster_1samp_test( X, buffer_size=None, n_jobs=2, n_permutations=1, seed=0, stat_fun=ttest_1samp_no_p, verbose=False) assert 'independently' not in log_file.getvalue() # ensure that non-independence yields warning stat_fun = partial(ttest_1samp_no_p, sigma=1e-3) if check_version('numpy', '1.17'): random_state = np.random.default_rng(0) else: random_state = 0 with pytest.warns(RuntimeWarning, match='independently'): permutation_cluster_1samp_test( X, buffer_size=10, n_jobs=2, n_permutations=1, seed=random_state, stat_fun=stat_fun, verbose=False) finally: if orig_dir is not None: os.environ['MNE_CACHE_DIR'] = orig_dir else: del os.environ['MNE_CACHE_DIR'] if orig_size is not None: os.environ['MNE_MEMMAP_MIN_SIZE'] = orig_size else: del os.environ['MNE_MEMMAP_MIN_SIZE']
def test_add_patch_info(monkeypatch): """Test adding patch info to source space.""" # let's setup a small source space src = _read_small_src(remove=False) src_new = _read_small_src() # test that no patch info is added for small dist_limit add_source_space_distances(src_new, dist_limit=0.00001) assert all(s['nearest'] is None for s in src_new) assert all(s['nearest_dist'] is None for s in src_new) assert all(s['pinfo'] is None for s in src_new) # now let's use one that works (and test our warning-throwing) with monkeypatch.context() as m: m.setattr(mne.source_space, '_DIST_WARN_LIMIT', 1) with pytest.warns(RuntimeWarning, match='Computing distances for 258'): add_source_space_distances(src_new) _compare_source_spaces(src, src_new, 'approx') # Old SciPy can't do patch info only src_new = _read_small_src() with monkeypatch.context() as m: m.setattr(scipy, '__version__', '1.0') with pytest.raises(RuntimeError, match='required to calculate patch '): add_source_space_distances(src_new, dist_limit=0) # New SciPy can if check_version('scipy', '1.3'): src_nodist = src.copy() for s in src_nodist: for key in ('dist', 'dist_limit'): s[key] = None add_source_space_distances(src_new, dist_limit=0) _compare_source_spaces(src, src_new, 'approx')
def test_read_raw_curry(fname, tol, preload, bdf_curry_ref): """Test reading CURRY files.""" with pytest.warns(None) as wrn: raw = read_raw_curry(fname, preload=preload) if not check_version('numpy', '1.16') and preload and fname.endswith('ASCII.dat'): assert len(wrn) > 0 else: assert len(wrn) == 0 assert hasattr(raw, '_data') == preload assert raw.n_times == bdf_curry_ref.n_times assert raw.info['sfreq'] == bdf_curry_ref.info['sfreq'] for field in ['kind', 'ch_name']: assert_array_equal([ch[field] for ch in raw.info['chs']], [ch[field] for ch in bdf_curry_ref.info['chs']]) raw.verbose = 'error' # don't emit warnings about slow reading assert_allclose(raw.get_data(), bdf_curry_ref.get_data(), atol=tol) picks, start, stop = ["C3", "C4"], 200, 800 assert_allclose(raw.get_data(picks=picks, start=start, stop=stop), bdf_curry_ref.get_data(picks=picks, start=start, stop=stop), rtol=tol) assert raw.info['dev_head_t'] is None
def test_bti(_bids_validate): """Test functionality of the write_raw_bids conversion for BTi data.""" bids_root = _TempDir() data_path = op.join(base_path, 'bti', 'tests', 'data') raw_fname = op.join(data_path, 'test_pdf_linux') config_fname = op.join(data_path, 'test_config_linux') headshape_fname = op.join(data_path, 'test_hs_linux') raw = mne.io.read_raw_bti(raw_fname, config_fname=config_fname, head_shape_fname=headshape_fname) # write the BIDS dataset description, then write BIDS files make_dataset_description(bids_root, name="BTi data") write_raw_bids(raw, bids_basename, bids_root, verbose=True) assert op.exists(op.join(bids_root, 'participants.tsv')) _bids_validate(bids_root) raw = read_raw_bids(bids_basename + '_meg', bids_root) with pytest.raises(TypeError, match="unexpected keyword argument 'foo'"): read_raw_bids(bids_basename + '_meg', bids_root, extra_params=dict(foo='bar')) if check_version('mne', '0.20'): # test anonymize raw = mne.io.read_raw_bti(raw_fname, config_fname=config_fname, head_shape_fname=headshape_fname) with pytest.warns(UserWarning, match='Converting to FIF for anonymization'): output_path = _test_anonymize(raw, bids_basename) _bids_validate(output_path)
def test_check(tmpdir): """Test checking functions.""" pytest.raises(ValueError, check_random_state, 'foo') pytest.raises(TypeError, _check_fname, 1) _check_fname(Path('./')) fname = str(tmpdir.join('foo')) with open(fname, 'wb'): pass assert op.isfile(fname) _check_fname(fname, overwrite='read', must_exist=True) orig_perms = os.stat(fname).st_mode os.chmod(fname, 0) if not sys.platform.startswith('win'): with pytest.raises(PermissionError, match='read permissions'): _check_fname(fname, overwrite='read', must_exist=True) os.chmod(fname, orig_perms) os.remove(fname) assert not op.isfile(fname) pytest.raises(IOError, check_fname, 'foo', 'tets-dip.x', (), ('.fif', )) pytest.raises(ValueError, _check_subject, None, None) pytest.raises(TypeError, _check_subject, None, 1) pytest.raises(TypeError, _check_subject, 1, None) # smoke tests for permitted types check_random_state(None).choice(1) check_random_state(0).choice(1) check_random_state(np.random.RandomState(0)).choice(1) if check_version('numpy', '1.17'): check_random_state(np.random.default_rng(0)).choice(1) # _meg.fif is a valid ending and should not raise an error new_fname = str( tmpdir.join(op.basename(fname_raw).replace('_raw.', '_meg.'))) shutil.copyfile(fname_raw, new_fname) mne.io.read_raw_fif(new_fname)
def test_ctf(_bids_validate): """Test functionality of the write_raw_bids conversion for CTF data.""" bids_root = _TempDir() data_path = op.join(testing.data_path(download=False), 'CTF') raw_fname = op.join(data_path, 'testdata_ctf.ds') raw = mne.io.read_raw_ctf(raw_fname) with pytest.warns(UserWarning, match='No line frequency'): write_raw_bids(raw, bids_basename, bids_root=bids_root) _bids_validate(bids_root) with pytest.warns(UserWarning, match='Did not find any events'): raw = read_raw_bids(bids_basename + '_meg.ds', bids_root, extra_params=dict(clean_names=False)) # test to check that running again with overwrite == False raises an error with pytest.raises(FileExistsError, match="already exists"): # noqa: F821 write_raw_bids(raw, bids_basename, bids_root=bids_root) assert op.exists(op.join(bids_root, 'participants.tsv')) # test anonymize if check_version('mne', '0.20'): raw = mne.io.read_raw_ctf(raw_fname) with pytest.warns(UserWarning, match='Converting to FIF for anonymization'): output_path = _test_anonymize(raw, bids_basename) _bids_validate(output_path) raw.set_meas_date(None) raw.anonymize() with pytest.raises(ValueError, match='All measurement dates are None'): get_anonymization_daysback(raw)
def test_check(tmp_path): """Test checking functions.""" pytest.raises(ValueError, check_random_state, 'foo') pytest.raises(TypeError, _check_fname, 1) _check_fname(Path('./foo')) fname = tmp_path / 'foo' with open(fname, 'wb'): pass assert op.isfile(fname) _check_fname(fname, overwrite='read', must_exist=True) orig_perms = os.stat(fname).st_mode os.chmod(fname, 0) if not sys.platform.startswith('win'): with pytest.raises(PermissionError, match='read permissions'): _check_fname(fname, overwrite='read', must_exist=True) os.chmod(fname, orig_perms) os.remove(fname) assert not op.isfile(fname) pytest.raises(IOError, check_fname, 'foo', 'tets-dip.x', (), ('.fif', )) pytest.raises(ValueError, _check_subject, None, None) pytest.raises(TypeError, _check_subject, None, 1) pytest.raises(TypeError, _check_subject, 1, None) # smoke tests for permitted types check_random_state(None).choice(1) check_random_state(0).choice(1) check_random_state(np.random.RandomState(0)).choice(1) if check_version('numpy', '1.17'): check_random_state(np.random.default_rng(0)).choice(1)
def test_simulate_sparse_stc_single_hemi(_get_fwd_labels): """Test generation of sparse source estimate.""" fwd, labels = _get_fwd_labels labels_single_hemi = labels[1:] # keep only labels in one hemisphere n_times = 10 tmin = 0 tstep = 1e-3 times = np.arange(n_times, dtype=np.float64) * tstep + tmin stc_1 = simulate_sparse_stc(fwd['src'], len(labels_single_hemi), times, labels=labels_single_hemi, random_state=0) assert (stc_1.data.shape[0] == len(labels_single_hemi)) assert (stc_1.data.shape[1] == n_times) # make sure we get the same result when using the same seed stc_2 = simulate_sparse_stc(fwd['src'], len(labels_single_hemi), times, labels=labels_single_hemi, random_state=0) assert_array_equal(stc_1.lh_vertno, stc_2.lh_vertno) assert_array_equal(stc_1.rh_vertno, stc_2.rh_vertno) # smoke test for new API if check_version('numpy', '1.17'): simulate_sparse_stc(fwd['src'], len(labels_single_hemi), times, labels=labels_single_hemi, random_state=np.random.default_rng(0))
def _patch_setup_dots(mode, info, coils, ch): """Monkey patch _setup_dots for MNE-Python >= v0.24.""" from mne.forward._field_interpolation import _setup_dots from mne.utils import check_version if not check_version('mne', '0.24'): return _setup_dots(mode, coils, ch) else: return _setup_dots(mode, info, coils, ch)
def _get_pca(rng=None): if not check_version('sklearn', '0.18'): from sklearn.decomposition import RandomizedPCA return RandomizedPCA(n_components=2, whiten=True, random_state=rng) else: from sklearn.decomposition import PCA return PCA(n_components=2, whiten=True, svd_solver='randomized', random_state=rng)
def test_decoding_time(): """Test TimeDecoding.""" from sklearn.svm import SVR if check_version('sklearn', '0.18'): from sklearn.model_selection import KFold else: from sklearn.cross_validation import KFold epochs = make_epochs() with warnings.catch_warnings(record=True): # dep tg = TimeDecoding() assert_equal("<TimeDecoding | no fit, no prediction, no score>", '%s' % tg) assert_true(hasattr(tg, 'times')) assert_true(not hasattr(tg, 'train_times')) assert_true(not hasattr(tg, 'test_times')) tg.fit(epochs) assert_equal( "<TimeDecoding | fitted, start : -0.200 (s), stop : 0.499 " "(s), no prediction, no score>", '%s' % tg) assert_true(not hasattr(tg, 'train_times_')) assert_true(not hasattr(tg, 'test_times_')) assert_raises(RuntimeError, tg.score, epochs=None) with warnings.catch_warnings(record=True): # not vectorizing tg.predict(epochs) assert_equal( "<TimeDecoding | fitted, start : -0.200 (s), stop : 0.499 " "(s), predicted 14 epochs, no score>", '%s' % tg) assert_array_equal(np.shape(tg.y_pred_), [15, 14, 1]) with warnings.catch_warnings(record=True): # not vectorizing tg.score(epochs) tg.score() assert_array_equal(np.shape(tg.scores_), [15]) assert_equal( "<TimeDecoding | fitted, start : -0.200 (s), stop : 0.499 " "(s), predicted 14 epochs,\n scored (accuracy_score)>", '%s' % tg) # Test with regressor clf = SVR() cv = KFold(len(epochs)) y = np.random.rand(len(epochs)) with warnings.catch_warnings(record=True): # dep tg = TimeDecoding(clf=clf, cv=cv) tg.fit(epochs, y=y) # Test scorer parameter to accept string epochs.crop(epochs.times[0], epochs.times[2]) with warnings.catch_warnings(record=True): # dep td_1 = TimeDecoding(scorer='accuracy') td_1.fit(epochs) score_1 = td_1.score(epochs) with warnings.catch_warnings(record=True): # dep td_2 = TimeDecoding() td_2.fit(epochs) score_2 = td_2.score(epochs) assert_array_equal(score_1, score_2) td_1.scorer = 'accuracies' assert_raises(KeyError, td_1.score, epochs)
def test_bdf(_bids_validate): """Test write_raw_bids conversion for Biosemi data.""" bids_root = _TempDir() data_path = op.join(base_path, 'edf', 'tests', 'data') raw_fname = op.join(data_path, 'test.bdf') raw = mne.io.read_raw_bdf(raw_fname) with pytest.warns(UserWarning, match='No line frequency found'): write_raw_bids(raw, bids_basename, bids_root, overwrite=False) _bids_validate(bids_root) # Test also the reading of channel types from channels.tsv # the first channel in the raw data is not MISC right now test_ch_idx = 0 assert coil_type(raw.info, test_ch_idx) != 'misc' # we will change the channel type to MISC and overwrite the channels file bids_fname = bids_basename + '_eeg.bdf' channels_fname = _find_matching_sidecar(bids_fname, bids_root, 'channels.tsv') channels_dict = _from_tsv(channels_fname) channels_dict['type'][test_ch_idx] = 'MISC' _to_tsv(channels_dict, channels_fname) # Now read the raw data back from BIDS, with the tampered TSV, to show # that the channels.tsv truly influences how read_raw_bids sets ch_types # in the raw data object raw = read_raw_bids(bids_fname, bids_root) assert coil_type(raw.info, test_ch_idx) == 'misc' with pytest.raises(TypeError, match="unexpected keyword argument 'foo'"): read_raw_bids(bids_fname, bids_root, extra_params=dict(foo='bar')) # Test cropped assertion error raw = mne.io.read_raw_bdf(raw_fname) raw.crop(0, raw.times[-2]) with pytest.raises(AssertionError, match='cropped'): write_raw_bids(raw, bids_basename, bids_root) # test anonymize and convert if check_version('mne', '0.20') and check_version('pybv', '0.2.0'): raw = mne.io.read_raw_bdf(raw_fname) output_path = _test_anonymize(raw, bids_basename) _bids_validate(output_path)
def test_decoding_time(): """Test TimeDecoding.""" from sklearn.svm import SVR if check_version('sklearn', '0.18'): from sklearn.model_selection import KFold else: from sklearn.cross_validation import KFold epochs = make_epochs() with warnings.catch_warnings(record=True): # dep tg = TimeDecoding() assert_equal("<TimeDecoding | no fit, no prediction, no score>", '%s' % tg) assert_true(hasattr(tg, 'times')) assert_true(not hasattr(tg, 'train_times')) assert_true(not hasattr(tg, 'test_times')) tg.fit(epochs) assert_equal("<TimeDecoding | fitted, start : -0.200 (s), stop : 0.499 " "(s), no prediction, no score>", '%s' % tg) assert_true(not hasattr(tg, 'train_times_')) assert_true(not hasattr(tg, 'test_times_')) assert_raises(RuntimeError, tg.score, epochs=None) with warnings.catch_warnings(record=True): # not vectorizing tg.predict(epochs) assert_equal("<TimeDecoding | fitted, start : -0.200 (s), stop : 0.499 " "(s), predicted 14 epochs, no score>", '%s' % tg) assert_array_equal(np.shape(tg.y_pred_), [15, 14, 1]) with warnings.catch_warnings(record=True): # not vectorizing tg.score(epochs) tg.score() assert_array_equal(np.shape(tg.scores_), [15]) assert_equal("<TimeDecoding | fitted, start : -0.200 (s), stop : 0.499 " "(s), predicted 14 epochs,\n scored (accuracy_score)>", '%s' % tg) # Test with regressor clf = SVR() cv = KFold(len(epochs)) y = np.random.rand(len(epochs)) with warnings.catch_warnings(record=True): # dep tg = TimeDecoding(clf=clf, cv=cv) tg.fit(epochs, y=y) # Test scorer parameter to accept string epochs.crop(epochs.times[0], epochs.times[2]) with warnings.catch_warnings(record=True): # dep td_1 = TimeDecoding(scorer='accuracy') td_1.fit(epochs) score_1 = td_1.score(epochs) with warnings.catch_warnings(record=True): # dep td_2 = TimeDecoding() td_2.fit(epochs) score_2 = td_2.score(epochs) assert_array_equal(score_1, score_2) td_1.scorer = 'accuracies' assert_raises(KeyError, td_1.score, epochs)
def test_inverse_coef(): """Test inverse coefficients computation.""" from sklearn.linear_model import Ridge rng = np.random.RandomState(0) tmin, tmax = 0., 10. n_feats, n_targets, n_samples = 64, 2, 10000 n_delays = int((tmax - tmin) + 1) def make_data(n_feats, n_targets, n_samples, tmin, tmax): X = rng.randn(n_samples, n_feats) w = rng.randn(int((tmax - tmin) + 1) * n_feats, n_targets) # Delay inputs X_del = np.concatenate(_delay_time_series(X, tmin, tmax, 1.).transpose(2, 0, 1), axis=1) y = np.dot(X_del, w) return X, y # Check coefficient dims, for all estimator types X, y = make_data(n_feats, n_targets, n_samples, tmin, tmax) tdr = TimeDelayingRidge(tmin, tmax, 1., 0.1, 'laplacian') for estimator in (0., 0.01, Ridge(alpha=0.), tdr): rf = ReceptiveField(tmin, tmax, 1., estimator=estimator, patterns=True) rf.fit(X, y) inv_rf = ReceptiveField(tmin, tmax, 1., estimator=estimator, patterns=True) inv_rf.fit(y, X) assert_array_equal(rf.coef_.shape, rf.patterns_.shape, (n_targets, n_feats, n_delays)) assert_array_equal(inv_rf.coef_.shape, inv_rf.patterns_.shape, (n_feats, n_targets, n_delays)) # we should have np.dot(patterns.T,coef) ~ np.eye(n) c0 = rf.coef_.reshape(n_targets, n_feats * n_delays) c1 = rf.patterns_.reshape(n_targets, n_feats * n_delays) assert_allclose(np.dot(c0, c1.T), np.eye(c0.shape[0]), atol=0.1) # Check that warnings are issued when no regularization is applied n_feats, n_targets, n_samples = 5, 60, 50 X, y = make_data(n_feats, n_targets, n_samples, tmin, tmax) for estimator in (0., Ridge(alpha=0.)): rf = ReceptiveField(tmin, tmax, 1., estimator=estimator, patterns=True) with warnings.catch_warnings(record=True) as w: rf.fit(y, X) # For some reason there is no warning if estimator and not check_version('numpy', '1.13'): continue assert_equal(len(w), 1) assert any(x in str(w[0].message).lower() for x in ('singular', 'scipy.linalg.solve'))
def _read_events(events_data, event_id, raw, ext, verbose=None): """Read in events data. Parameters ---------- events_data : str | array | None The events file. If a string, a path to the events file. If an array, the MNE events array (shape n_events, 3). If None, events will be inferred from the stim channel using `find_events`. event_id : dict The event id dict used to create a 'trial_type' column in events.tsv, mapping a description key to an integer valued event code. raw : instance of Raw The data as MNE-Python Raw object. ext : str The extension of the original data file. verbose : bool | str | int | None If not None, override default verbose level (see :func:`mne.verbose`). Returns ------- events : array, shape = (n_events, 3) The first column contains the event time in samples and the third column contains the event id. The second column is ignored for now but typically contains the value of the trigger channel either immediately before the event or immediately after. """ if isinstance(events_data, str): events = read_events(events_data, verbose=verbose).astype(int) elif isinstance(events_data, np.ndarray): if events_data.ndim != 2: raise ValueError('Events must have two dimensions, ' 'found %s' % events_data.ndim) if events_data.shape[1] != 3: raise ValueError('Events must have second dimension of length 3, ' 'found %s' % events_data.shape[1]) events = events_data elif 'stim' in raw: events = find_events(raw, min_duration=0.001, initial_event=True, verbose=verbose) elif ext in ['.vhdr', '.set'] and check_version('mne', '0.18'): events, event_id = events_from_annotations(raw, event_id, verbose=verbose) else: warn('No events found or provided. Please make sure to' ' set channel type using raw.set_channel_types' ' or provide events_data.') events = None return events, event_id
def test_xdawn_regularization(): """Test Xdawn with regularization.""" # Get data, this time MEG so we can test proper reg/ch type support raw = read_raw_fif(raw_fname, verbose=False, preload=True) events = read_events(event_name) picks = pick_types(raw.info, meg=True, eeg=False, stim=False, ecg=False, eog=False, exclude='bads')[::8] raw.pick_channels([raw.ch_names[pick] for pick in picks]) del picks raw.info.normalize_proj() epochs = Epochs(raw, events, event_id, tmin, tmax, preload=True, baseline=None, verbose=False) # Test with overlapping events. # modify events to simulate one overlap events = epochs.events sel = np.where(events[:, 2] == 2)[0][:2] modified_event = events[sel[0]] modified_event[0] += 1 epochs.events[sel[1]] = modified_event # Fit and check that overlap was found and applied xd = Xdawn(n_components=2, correct_overlap='auto', reg='oas') xd.fit(epochs) assert xd.correct_overlap_ evoked = epochs['cond2'].average() assert np.sum(np.abs(evoked.data - xd.evokeds_['cond2'].data)) # With covariance regularization for reg in [.1, 0.1, 'ledoit_wolf', 'oas']: xd = Xdawn(n_components=2, correct_overlap=False, signal_cov=np.eye(len(epochs.ch_names)), reg=reg) xd.fit(epochs) # With bad shrinkage xd = Xdawn(n_components=2, correct_overlap=False, signal_cov=np.eye(len(epochs.ch_names)), reg=2) with pytest.raises(ValueError, match='shrinkage must be'): xd.fit(epochs) # With rank-deficient input # this is a bit wacky because `epochs` has projectors on from the old raw # but it works as a rank-deficient test case xd = Xdawn(correct_overlap=False, reg=0.5) xd.fit(epochs) xd = Xdawn(correct_overlap=False, reg='diagonal_fixed') xd.fit(epochs) bad_eig = (sys.platform.startswith('win') and check_version('numpy', '1.16.5') and 'mkl_rt' in _get_numpy_libs()) # some problem with MKL on Win if bad_eig: pytest.skip('Unknown MKL+Windows error fails for eig check') xd = Xdawn(correct_overlap=False, reg=None) with pytest.raises(ValueError, match='Could not compute eigenvalues'): xd.fit(epochs)
def test_inverse_coef(): """Test inverse coefficients computation.""" from sklearn.linear_model import Ridge rng = np.random.RandomState(0) tmin, tmax = 0., 10. n_feats, n_targets, n_samples = 64, 2, 10000 n_delays = int((tmax - tmin) + 1) def make_data(n_feats, n_targets, n_samples, tmin, tmax): X = rng.randn(n_samples, n_feats) w = rng.randn(int((tmax - tmin) + 1) * n_feats, n_targets) # Delay inputs X_del = np.concatenate( _delay_time_series(X, tmin, tmax, 1.).transpose(2, 0, 1), axis=1) y = np.dot(X_del, w) return X, y # Check coefficient dims, for all estimator types X, y = make_data(n_feats, n_targets, n_samples, tmin, tmax) tdr = TimeDelayingRidge(tmin, tmax, 1., 0.1, 'laplacian') for estimator in (0., 0.01, Ridge(alpha=0.), tdr): rf = ReceptiveField(tmin, tmax, 1., estimator=estimator, patterns=True) rf.fit(X, y) inv_rf = ReceptiveField(tmin, tmax, 1., estimator=estimator, patterns=True) inv_rf.fit(y, X) assert_array_equal(rf.coef_.shape, rf.patterns_.shape, (n_targets, n_feats, n_delays)) assert_array_equal(inv_rf.coef_.shape, inv_rf.patterns_.shape, (n_feats, n_targets, n_delays)) # we should have np.dot(patterns.T,coef) ~ np.eye(n) c0 = rf.coef_.reshape(n_targets, n_feats * n_delays) c1 = rf.patterns_.reshape(n_targets, n_feats * n_delays) assert_allclose(np.dot(c0, c1.T), np.eye(c0.shape[0]), atol=0.1) # Check that warnings are issued when no regularization is applied n_feats, n_targets, n_samples = 5, 60, 50 X, y = make_data(n_feats, n_targets, n_samples, tmin, tmax) for estimator in (0., Ridge(alpha=0.)): rf = ReceptiveField(tmin, tmax, 1., estimator=estimator, patterns=True) with warnings.catch_warnings(record=True) as w: rf.fit(y, X) # For some reason there is no warning if estimator and not check_version('numpy', '1.13'): continue assert_equal(len(w), 1) assert_true(any(x in str(w[0].message).lower() for x in ('singular', 'scipy.linalg.solve')), msg=str(w[0].message))
def _read_raw(raw_path, electrode=None, hsp=None, hpi=None, allow_maxshield=False, config_path=None, **kwargs): """Read a raw file into MNE, making inferences based on extension.""" _, ext = _parse_ext(raw_path) # KIT systems if ext in ['.con', '.sqd']: raw = io.read_raw_kit(raw_path, elp=electrode, hsp=hsp, mrk=hpi, preload=False, **kwargs) # BTi systems elif ext == '.pdf': raw = io.read_raw_bti( pdf_fname=str(raw_path), # FIXME MNE should accept Path! config_fname=str(config_path), # FIXME MNE should accept Path! head_shape_fname=hsp, preload=False, **kwargs) elif ext == '.fif': raw = reader[ext](raw_path, allow_maxshield, **kwargs) elif ext in ['.ds', '.vhdr', '.set', '.edf', '.bdf', '.EDF', '.snirf']: if (ext == '.snirf' and not check_version('mne', '1.0')): # pragma: no cover raise RuntimeError( 'fNIRS support in MNE-BIDS requires MNE-Python version 1.0') raw_path = Path(raw_path) raw = reader[ext](raw_path, **kwargs) # MEF and NWB are allowed, but not yet implemented elif ext in ['.mef', '.nwb']: raise ValueError(f'Got "{ext}" as extension. This is an allowed ' f'extension but there is no IO support for this ' f'file format yet.') # No supported data found ... # --------------------------- else: raise ValueError(f'Raw file name extension must be one ' f'of {ALLOWED_DATATYPE_EXTENSIONS}\n' f'Got {ext}') return raw
def test_plot_head_positions(): """Test plotting of head positions.""" import matplotlib.pyplot as plt pos = np.random.RandomState(0).randn(4, 10) pos[:, 0] = np.arange(len(pos)) with warnings.catch_warnings(record=True): # old MPL will cause a warning plot_head_positions(pos) if check_version('matplotlib', '1.4'): plot_head_positions(pos, mode='field') else: assert_raises(RuntimeError, plot_head_positions, pos, mode='field') assert_raises(ValueError, plot_head_positions, pos, 'foo') plt.close('all')
def _interpolate_bads_meg(inst, mode='accurate', origin=None, verbose=None): """Interpolate bad channels from data in good channels. Parameters ---------- inst : mne.io.Raw, mne.Epochs or mne.Evoked The data to interpolate. Must be preloaded. mode : str Either `'accurate'` or `'fast'`, determines the quality of the Legendre polynomial expansion used for interpolation. `'fast'` should be sufficient for most applications. origin : None | list If None, origin is set to sensor center of mass, otherwise use the coordinates provided as origin. The old standard value is (0., 0., 0.04) verbose : bool, str, int, or None If not None, override default verbose level (see :func:`mne.verbose` and :ref:`Logging documentation <tut_logging>` for more). """ from mne.channels.interpolation import _do_interp_dots picks_meg = pick_types(inst.info, meg=True, eeg=False, exclude=[]) picks_good = pick_types(inst.info, meg=True, eeg=False, exclude='bads') meg_ch_names = [inst.info['ch_names'][p] for p in picks_meg] bads_meg = [ch for ch in inst.info['bads'] if ch in meg_ch_names] # select the bad meg channel to be interpolated if len(bads_meg) == 0: picks_bad = [] else: picks_bad = pick_channels(inst.info['ch_names'], bads_meg, exclude=[]) # return without doing anything if there are no meg channels if len(picks_meg) == 0 or len(picks_bad) == 0: return info_from = pick_info(inst.info, picks_good) info_to = pick_info(inst.info, picks_bad) if check_version('mne', min_version='0.21'): from mne.forward import _map_meg_or_eeg_channels mapping = _map_meg_or_eeg_channels(info_from, info_to, mode=mode, origin=origin) else: from mne.forward import _map_meg_channels mapping = _map_meg_channels(info_from, info_to, mode=mode, origin=origin) _do_interp_dots(inst, mapping, picks_good, picks_bad)
def test_ci(): """Test confidence intervals.""" # isolated test of CI functions arr = np.linspace(0, 1, 1000)[..., np.newaxis] assert_allclose(_ci(arr, method="parametric"), _ci(arr, method="bootstrap"), rtol=.005) assert_allclose(_bootstrap_ci(arr, stat_fun="median", random_state=0), _bootstrap_ci(arr, stat_fun="mean", random_state=0), rtol=.1) # smoke test for new API if check_version('numpy', '1.17'): random_state = np.random.default_rng(0) _bootstrap_ci(arr, random_state=random_state)
def test_run_update_age_records(tmpdir): """Test Sleep Physionet URL handling.""" import pandas as pd fname = op.join(str(tmpdir), "records.csv") _update_sleep_age_records(fname) data = pd.read_csv(fname) if not check_version('pandas', '0.23.0'): expected = pd.read_csv(AGE_SLEEP_RECORDS) assert_array_equal( data[['subject', 'sha', 'fname']].values, expected[['subject', 'sha', 'fname']].values, ) else: pd.testing.assert_frame_equal(data, pd.read_csv(AGE_SLEEP_RECORDS))
def test_add_noise(): """Test noise addition.""" if check_version('numpy', '1.17'): rng = np.random.default_rng(0) else: rng = np.random.RandomState(0) raw = read_raw_fif(raw_fname) raw.del_proj() picks = pick_types(raw.info, meg=True, eeg=True, exclude=()) cov = compute_raw_covariance(raw, picks=picks) with pytest.raises(RuntimeError, match='to be loaded'): add_noise(raw, cov) raw.crop(0, 1).load_data() with pytest.raises(TypeError, match='Raw, Epochs, or Evoked'): add_noise(0., cov) with pytest.raises(TypeError, match='Covariance'): add_noise(raw, 0.) # test a no-op (data preserved) orig_data = raw[:][0] zero_cov = cov.copy() zero_cov['data'].fill(0) add_noise(raw, zero_cov) new_data = raw[:][0] assert_allclose(orig_data, new_data, atol=1e-30) # set to zero to make comparisons easier raw._data[:] = 0. epochs = EpochsArray(np.zeros((1, len(raw.ch_names), 100)), raw.info.copy()) epochs.info['bads'] = [] evoked = epochs.average(picks=np.arange(len(raw.ch_names))) for inst in (raw, epochs, evoked): with catch_logging() as log: add_noise(inst, cov, random_state=rng, verbose=True) log = log.getvalue() want = ('to {0}/{1} channels ({0}' .format(len(cov['names']), len(raw.ch_names))) assert want in log if inst is evoked: inst = EpochsArray(inst.data[np.newaxis], inst.info) if inst is raw: cov_new = compute_raw_covariance(inst, picks=picks) else: cov_new = compute_covariance(inst) assert cov['names'] == cov_new['names'] r = np.corrcoef(cov['data'].ravel(), cov_new['data'].ravel())[0, 1] assert r > 0.99
def test_check(): """Test checking functions.""" pytest.raises(ValueError, check_random_state, 'foo') pytest.raises(TypeError, _check_fname, 1) pytest.raises(IOError, check_fname, 'foo', 'tets-dip.x', (), ('.fif', )) pytest.raises(ValueError, _check_subject, None, None) pytest.raises(TypeError, _check_subject, None, 1) pytest.raises(TypeError, _check_subject, 1, None) # smoke tests for permitted types check_random_state(None).choice(1) check_random_state(0).choice(1) check_random_state(np.random.RandomState(0)).choice(1) if check_version('numpy', '1.17'): check_random_state(np.random.default_rng(0)).choice(1) # _meg.fif is a valid ending and should not raise an error sh.copyfile(fname_raw, fname_raw.replace('_raw.', '_meg.')) mne.io.read_raw_fif(fname_raw.replace('_raw.', '_meg.'))
def test_find_emptyroom_ties(): """Test that we receive a warning on a date tie.""" data_path = testing.data_path() raw_fname = op.join(data_path, 'MEG', 'sample', 'sample_audvis_trunc_raw.fif') bids_root = _TempDir() bids_path.update(root=bids_root) session = '20010101' er_dir_path = BIDSPath(subject='emptyroom', session=session, datatype='meg', root=bids_root) er_dir = er_dir_path.mkdir().directory meas_date = (datetime.strptime(session, '%Y%m%d').replace(tzinfo=timezone.utc)) raw = _read_raw_fif(raw_fname) er_raw_fname = op.join(data_path, 'MEG', 'sample', 'ernoise_raw.fif') raw.copy().crop(0, 10).save(er_raw_fname, overwrite=True) er_raw = _read_raw_fif(er_raw_fname) if check_version('mne', '0.20'): raw.set_meas_date(meas_date) er_raw.set_meas_date(meas_date) else: raw.info['meas_date'] = (meas_date.timestamp(), 0) er_raw.info['meas_date'] = (meas_date.timestamp(), 0) write_raw_bids(raw, bids_path, overwrite=True) er_bids_path = BIDSPath(subject='emptyroom', session=session) er_basename_1 = er_bids_path.basename er_basename_2 = BIDSPath(subject='emptyroom', session=session, task='noise').basename er_raw.save(op.join(er_dir, f'{er_basename_1}_meg.fif')) er_raw.save(op.join(er_dir, f'{er_basename_2}_meg.fif')) with pytest.warns(RuntimeWarning, match='Found more than one'): bids_path.find_empty_room()
def test_generalization_across_time(): """Test time generalization decoding """ from sklearn.svm import SVC from sklearn.base import is_classifier # KernelRidge is used for testing 1) regression analyses 2) n-dimensional # predictions. from sklearn.kernel_ridge import KernelRidge from sklearn.preprocessing import LabelEncoder from sklearn.metrics import roc_auc_score, mean_squared_error epochs = make_epochs() y_4classes = np.hstack((epochs.events[:7, 2], epochs.events[7:, 2] + 1)) if check_version('sklearn', '0.18'): from sklearn.model_selection import (KFold, StratifiedKFold, ShuffleSplit, LeaveOneLabelOut) cv_shuffle = ShuffleSplit() cv = LeaveOneLabelOut() # XXX we cannot pass any other parameters than X and y to cv.split # so we have to build it before hand cv_lolo = [(train, test) for train, test in cv.split( X=y_4classes, y=y_4classes, labels=y_4classes)] # With sklearn >= 0.17, `clf` can be identified as a regressor, and # the scoring metrics can therefore be automatically assigned. scorer_regress = None else: from sklearn.cross_validation import (KFold, StratifiedKFold, ShuffleSplit, LeaveOneLabelOut) cv_shuffle = ShuffleSplit(len(epochs)) cv_lolo = LeaveOneLabelOut(y_4classes) # With sklearn < 0.17, `clf` cannot be identified as a regressor, and # therefore the scoring metrics cannot be automatically assigned. scorer_regress = mean_squared_error # Test default running gat = GeneralizationAcrossTime(picks='foo') assert_equal("<GAT | no fit, no prediction, no score>", "%s" % gat) assert_raises(ValueError, gat.fit, epochs) with warnings.catch_warnings(record=True): # check classic fit + check manual picks gat.picks = [0] gat.fit(epochs) # check optional y as array gat.picks = None gat.fit(epochs, y=epochs.events[:, 2]) # check optional y as list gat.fit(epochs, y=epochs.events[:, 2].tolist()) assert_equal(len(gat.picks_), len(gat.ch_names), 1) assert_equal("<GAT | fitted, start : -0.200 (s), stop : 0.499 (s), no " "prediction, no score>", '%s' % gat) assert_equal(gat.ch_names, epochs.ch_names) # test different predict function: gat = GeneralizationAcrossTime(predict_method='decision_function') gat.fit(epochs) # With classifier, the default cv is StratifiedKFold assert_true(gat.cv_.__class__ == StratifiedKFold) gat.predict(epochs) assert_array_equal(np.shape(gat.y_pred_), (15, 15, 14, 1)) gat.predict_method = 'predict_proba' gat.predict(epochs) assert_array_equal(np.shape(gat.y_pred_), (15, 15, 14, 2)) gat.predict_method = 'foo' assert_raises(NotImplementedError, gat.predict, epochs) gat.predict_method = 'predict' gat.predict(epochs) assert_array_equal(np.shape(gat.y_pred_), (15, 15, 14, 1)) assert_equal("<GAT | fitted, start : -0.200 (s), stop : 0.499 (s), " "predicted 14 epochs, no score>", "%s" % gat) gat.score(epochs) assert_true(gat.scorer_.__name__ == 'accuracy_score') # check clf / predict_method combinations for which the scoring metrics # cannot be inferred. gat.scorer = None gat.predict_method = 'decision_function' assert_raises(ValueError, gat.score, epochs) # Check specifying y manually gat.predict_method = 'predict' gat.score(epochs, y=epochs.events[:, 2]) gat.score(epochs, y=epochs.events[:, 2].tolist()) assert_equal("<GAT | fitted, start : -0.200 (s), stop : 0.499 (s), " "predicted 14 epochs,\n scored " "(accuracy_score)>", "%s" % gat) with warnings.catch_warnings(record=True): gat.fit(epochs, y=epochs.events[:, 2]) old_mode = gat.predict_mode gat.predict_mode = 'super-foo-mode' assert_raises(ValueError, gat.predict, epochs) gat.predict_mode = old_mode gat.score(epochs, y=epochs.events[:, 2]) assert_true("accuracy_score" in '%s' % gat.scorer_) epochs2 = epochs.copy() # check _DecodingTime class assert_equal("<DecodingTime | start: -0.200 (s), stop: 0.499 (s), step: " "0.050 (s), length: 0.050 (s), n_time_windows: 15>", "%s" % gat.train_times_) assert_equal("<DecodingTime | start: -0.200 (s), stop: 0.499 (s), step: " "0.050 (s), length: 0.050 (s), n_time_windows: 15 x 15>", "%s" % gat.test_times_) # the y-check gat.predict_mode = 'mean-prediction' epochs2.events[:, 2] += 10 gat_ = copy.deepcopy(gat) with use_log_level('error'): assert_raises(ValueError, gat_.score, epochs2) gat.predict_mode = 'cross-validation' # Test basics # --- number of trials assert_true(gat.y_train_.shape[0] == gat.y_true_.shape[0] == len(gat.y_pred_[0][0]) == 14) # --- number of folds assert_true(np.shape(gat.estimators_)[1] == gat.cv) # --- length training size assert_true(len(gat.train_times_['slices']) == 15 == np.shape(gat.estimators_)[0]) # --- length testing sizes assert_true(len(gat.test_times_['slices']) == 15 == np.shape(gat.scores_)[0]) assert_true(len(gat.test_times_['slices'][0]) == 15 == np.shape(gat.scores_)[1]) # Test score_mode gat.score_mode = 'foo' assert_raises(ValueError, gat.score, epochs) gat.score_mode = 'fold-wise' scores = gat.score(epochs) assert_array_equal(np.shape(scores), [15, 15, 5]) gat.score_mode = 'mean-sample-wise' scores = gat.score(epochs) assert_array_equal(np.shape(scores), [15, 15]) gat.score_mode = 'mean-fold-wise' scores = gat.score(epochs) assert_array_equal(np.shape(scores), [15, 15]) gat.predict_mode = 'mean-prediction' with warnings.catch_warnings(record=True) as w: gat.score(epochs) assert_true(any("score_mode changed from " in str(ww.message) for ww in w)) # Test longer time window gat = GeneralizationAcrossTime(train_times={'length': .100}) with warnings.catch_warnings(record=True): gat2 = gat.fit(epochs) assert_true(gat is gat2) # return self assert_true(hasattr(gat2, 'cv_')) assert_true(gat2.cv_ != gat.cv) with warnings.catch_warnings(record=True): # not vectorizing scores = gat.score(epochs) assert_true(isinstance(scores, np.ndarray)) # type check assert_equal(len(scores[0]), len(scores)) # shape check assert_equal(len(gat.test_times_['slices'][0][0]), 2) # Decim training steps gat = GeneralizationAcrossTime(train_times={'step': .100}) with warnings.catch_warnings(record=True): gat.fit(epochs) gat.score(epochs) assert_true(len(gat.scores_) == len(gat.estimators_) == 8) # training time assert_equal(len(gat.scores_[0]), 15) # testing time # Test start stop training & test cv without n_fold params y_4classes = np.hstack((epochs.events[:7, 2], epochs.events[7:, 2] + 1)) train_times = dict(start=0.090, stop=0.250) gat = GeneralizationAcrossTime(cv=cv_lolo, train_times=train_times) # predict without fit assert_raises(RuntimeError, gat.predict, epochs) with warnings.catch_warnings(record=True): gat.fit(epochs, y=y_4classes) gat.score(epochs) assert_equal(len(gat.scores_), 4) assert_equal(gat.train_times_['times'][0], epochs.times[6]) assert_equal(gat.train_times_['times'][-1], epochs.times[9]) # Test score without passing epochs & Test diagonal decoding gat = GeneralizationAcrossTime(test_times='diagonal') with warnings.catch_warnings(record=True): # not vectorizing gat.fit(epochs) assert_raises(RuntimeError, gat.score) with warnings.catch_warnings(record=True): # not vectorizing gat.predict(epochs) scores = gat.score() assert_true(scores is gat.scores_) assert_equal(np.shape(gat.scores_), (15, 1)) assert_array_equal([tim for ttime in gat.test_times_['times'] for tim in ttime], gat.train_times_['times']) # Test generalization across conditions gat = GeneralizationAcrossTime(predict_mode='mean-prediction', cv=2) with warnings.catch_warnings(record=True): gat.fit(epochs[0:6]) with warnings.catch_warnings(record=True): # There are some empty test folds because of n_trials gat.predict(epochs[7:]) gat.score(epochs[7:]) # Test training time parameters gat_ = copy.deepcopy(gat) # --- start stop outside time range gat_.train_times = dict(start=-999.) with use_log_level('error'): assert_raises(ValueError, gat_.fit, epochs) gat_.train_times = dict(start=999.) assert_raises(ValueError, gat_.fit, epochs) # --- impossible slices gat_.train_times = dict(step=.000001) assert_raises(ValueError, gat_.fit, epochs) gat_.train_times = dict(length=.000001) assert_raises(ValueError, gat_.fit, epochs) gat_.train_times = dict(length=999.) assert_raises(ValueError, gat_.fit, epochs) # Test testing time parameters # --- outside time range gat.test_times = dict(start=-999.) with warnings.catch_warnings(record=True): # no epochs in fold assert_raises(ValueError, gat.predict, epochs) gat.test_times = dict(start=999.) with warnings.catch_warnings(record=True): # no test epochs assert_raises(ValueError, gat.predict, epochs) # --- impossible slices gat.test_times = dict(step=.000001) with warnings.catch_warnings(record=True): # no test epochs assert_raises(ValueError, gat.predict, epochs) gat_ = copy.deepcopy(gat) gat_.train_times_['length'] = .000001 gat_.test_times = dict(length=.000001) with warnings.catch_warnings(record=True): # no test epochs assert_raises(ValueError, gat_.predict, epochs) # --- test time region of interest gat.test_times = dict(step=.150) with warnings.catch_warnings(record=True): # not vectorizing gat.predict(epochs) assert_array_equal(np.shape(gat.y_pred_), (15, 5, 14, 1)) # --- silly value gat.test_times = 'foo' with warnings.catch_warnings(record=True): # no test epochs assert_raises(ValueError, gat.predict, epochs) assert_raises(RuntimeError, gat.score) # --- unmatched length between training and testing time gat.test_times = dict(length=.150) assert_raises(ValueError, gat.predict, epochs) # --- irregular length training and testing times # 2 estimators, the first one is trained on two successive time samples # whereas the second one is trained on a single time sample. train_times = dict(slices=[[0, 1], [1]]) # The first estimator is tested once, the second estimator is tested on # two successive time samples. test_times = dict(slices=[[[0, 1]], [[0], [1]]]) gat = GeneralizationAcrossTime(train_times=train_times, test_times=test_times) gat.fit(epochs) with warnings.catch_warnings(record=True): # not vectorizing gat.score(epochs) assert_array_equal(np.shape(gat.y_pred_[0]), [1, len(epochs), 1]) assert_array_equal(np.shape(gat.y_pred_[1]), [2, len(epochs), 1]) # check cannot Automatically infer testing times for adhoc training times gat.test_times = None assert_raises(ValueError, gat.predict, epochs) svc = SVC(C=1, kernel='linear', probability=True) gat = GeneralizationAcrossTime(clf=svc, predict_mode='mean-prediction') with warnings.catch_warnings(record=True): gat.fit(epochs) # sklearn needs it: c.f. # https://github.com/scikit-learn/scikit-learn/issues/2723 # and http://bit.ly/1u7t8UT with use_log_level('error'): assert_raises(ValueError, gat.score, epochs2) gat.score(epochs) assert_true(0.0 <= np.min(scores) <= 1.0) assert_true(0.0 <= np.max(scores) <= 1.0) # Test that gets error if train on one dataset, test on another, and don't # specify appropriate cv: gat = GeneralizationAcrossTime(cv=cv_shuffle) gat.fit(epochs) with warnings.catch_warnings(record=True): gat.fit(epochs) gat.predict(epochs) assert_raises(ValueError, gat.predict, epochs[:10]) # Make CV with some empty train and test folds: # --- empty test fold(s) should warn when gat.predict() gat._cv_splits[0] = [gat._cv_splits[0][0], np.empty(0)] with warnings.catch_warnings(record=True) as w: gat.predict(epochs) assert_true(len(w) > 0) assert_true(any('do not have any test epochs' in str(ww.message) for ww in w)) # --- empty train fold(s) should raise when gat.fit() gat = GeneralizationAcrossTime(cv=[([0], [1]), ([], [0])]) assert_raises(ValueError, gat.fit, epochs[:2]) # Check that still works with classifier that output y_pred with # shape = (n_trials, 1) instead of (n_trials,) if check_version('sklearn', '0.17'): # no is_regressor before v0.17 gat = GeneralizationAcrossTime(clf=KernelRidge(), cv=2) epochs.crop(None, epochs.times[2]) gat.fit(epochs) # With regression the default cv is KFold and not StratifiedKFold assert_true(gat.cv_.__class__ == KFold) gat.score(epochs) # with regression the default scoring metrics is mean squared error assert_true(gat.scorer_.__name__ == 'mean_squared_error') # Test combinations of complex scenarios # 2 or more distinct classes n_classes = [2, 4] # 4 tested # nicely ordered labels or not le = LabelEncoder() y = le.fit_transform(epochs.events[:, 2]) y[len(y) // 2:] += 2 ys = (y, y + 1000) # Univariate and multivariate prediction svc = SVC(C=1, kernel='linear', probability=True) reg = KernelRidge() def scorer_proba(y_true, y_pred): return roc_auc_score(y_true, y_pred[:, 0]) # We re testing 3 scenario: default, classifier + predict_proba, regressor scorers = [None, scorer_proba, scorer_regress] predict_methods = [None, 'predict_proba', None] clfs = [svc, svc, reg] # Test all combinations for clf, predict_method, scorer in zip(clfs, predict_methods, scorers): for y in ys: for n_class in n_classes: for predict_mode in ['cross-validation', 'mean-prediction']: # Cannot use AUC for n_class > 2 if (predict_method == 'predict_proba' and n_class != 2): continue y_ = y % n_class with warnings.catch_warnings(record=True): gat = GeneralizationAcrossTime( cv=2, clf=clf, scorer=scorer, predict_mode=predict_mode) gat.fit(epochs, y=y_) gat.score(epochs, y=y_) # Check that scorer is correctly defined manually and # automatically. scorer_name = gat.scorer_.__name__ if scorer is None: if is_classifier(clf): assert_equal(scorer_name, 'accuracy_score') else: assert_equal(scorer_name, 'mean_squared_error') else: assert_equal(scorer_name, scorer.__name__)
def test_ems(): """Test event-matched spatial filters""" raw = io.read_raw_fif(raw_fname, preload=False, add_eeg_ref=False) # create unequal number of events events = read_events(event_name) events[-2, 2] = 3 picks = pick_types(raw.info, meg=True, stim=False, ecg=False, eog=False, exclude='bads') picks = picks[1:13:3] epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks, baseline=(None, 0), preload=True, add_eeg_ref=False) assert_raises(ValueError, compute_ems, epochs, ['aud_l', 'vis_l']) epochs = epochs.equalize_event_counts(epochs.event_id, copy=False)[0] assert_raises(KeyError, compute_ems, epochs, ['blah', 'hahah']) surrogates, filters, conditions = compute_ems(epochs) assert_equal(list(set(conditions)), [1, 3]) events = read_events(event_name) event_id2 = dict(aud_l=1, aud_r=2, vis_l=3) epochs = Epochs(raw, events, event_id2, tmin, tmax, picks=picks, baseline=(None, 0), preload=True, add_eeg_ref=False) epochs = epochs.equalize_event_counts(epochs.event_id, copy=False)[0] n_expected = sum([len(epochs[k]) for k in ['aud_l', 'vis_l']]) assert_raises(ValueError, compute_ems, epochs) surrogates, filters, conditions = compute_ems(epochs, ['aud_r', 'vis_l']) assert_equal(n_expected, len(surrogates)) assert_equal(n_expected, len(conditions)) assert_equal(list(set(conditions)), [2, 3]) # test compute_ems cv epochs = epochs['aud_r', 'vis_l'] epochs.equalize_event_counts(epochs.event_id) if check_version('sklearn', '0.18'): from sklearn.model_selection import StratifiedKFold cv = StratifiedKFold() else: from sklearn.cross_validation import StratifiedKFold cv = StratifiedKFold(epochs.events[:, 2]) compute_ems(epochs, cv=cv) compute_ems(epochs, cv=2) assert_raises(ValueError, compute_ems, epochs, cv='foo') assert_raises(ValueError, compute_ems, epochs, cv=len(epochs) + 1) raw.close() # EMS transformer, check that identical to compute_ems X = epochs.get_data() y = epochs.events[:, 2] X = X / np.std(X) # X scaled outside cv in compute_ems Xt, coefs = list(), list() ems = EMS() assert_equal(ems.__repr__(), '<EMS: not fitted.>') # manual leave-one-out to avoid sklearn version problem for test in range(len(y)): train = np.setdiff1d(range(len(y)), test) ems.fit(X[train], y[train]) coefs.append(ems.filters_) Xt.append(ems.transform(X[[test]])) assert_equal(ems.__repr__(), '<EMS: fitted with 4 filters on 2 classes.>') assert_array_almost_equal(filters, np.mean(coefs, axis=0)) assert_array_almost_equal(surrogates, np.vstack(Xt))