def test_stats(self): # FFX ds = DatasetEphy(x, roi=roi, times=times) WfConnComod(inference='ffx').fit(ds, **kw_conn) # RFX ds = DatasetEphy(x, roi=roi, times=times) WfConnComod(inference='rfx').fit(ds, **kw_conn)
def test_get_connectivity_pairs(self): """Test function get_connectivity_pairs.""" d_3d = self._get_data(3) ds = DatasetEphy(d_3d, times='times', **kw) for direction in [True, False]: for blocks in [True, False]: df_1, df_2 = ds.get_connectivity_pairs(directed=direction, as_blocks=blocks, verbose=False) assert isinstance(df_1, pd.DataFrame) assert isinstance(df_2, pd.DataFrame)
def test_multiconditions(self): """Test multi-conditions remapping.""" d_3d = self._get_data(3) ds = DatasetEphy(d_3d, y=[np.c_[k, i] for k, i in zip(y_int, z)], **kw) y_s1, y_s2 = ds.x[0]['y'].data, ds.x[1]['y'].data np.testing.assert_array_equal(y_s1, [0] * 4 + [1] + [2] * 5) np.testing.assert_array_equal(y_s2, [3] * 2 + [2] * 3 + [1] + [4] * 4)
def test_get_roi_data(self): """Test getting the data of a single brain region.""" # build dataset d_3d = self._get_data(3) ds = DatasetEphy(d_3d, y='y', z='z', **kw) # get the data ds_roi2 = ds.get_roi_data("roi_2", copnorm=False) np.testing.assert_array_equal(ds_roi2.shape, (100, 1, 20)) # test the data s1_r2, s2_r2 = d_3d[0].sel(roi='roi_2'), d_3d[1].sel(roi='roi_2') s12 = xr.concat((s1_r2, s2_r2), 'trials').T.expand_dims('mv', axis=-2) np.testing.assert_array_equal(ds_roi2.data, s12.data) # test task-related variables y_12, z_12 = np.r_[y_int[0], y_int[1]], np.r_[z[0], z[1]] np.testing.assert_array_equal(y_12, ds_roi2['y'].data) np.testing.assert_array_equal(z_12, ds_roi2['z'].data)
def test_no_stat(self): """Test on no stats / no permutations / don't repeat computations.""" y, gt = sim_mi_cc(x, snr=1.) dt = DatasetEphy(x, y, roi, times=time) # compute permutations but not statistics kernel = np.hanning(3) wf = WfMi('cc', 'ffx', kernel=kernel, verbose=False) assert isinstance(wf.wf_stats, WfStats) wf.fit(dt, mcp='nostat', **kw_mi) assert len(wf.mi) == len(wf.mi_p) == n_roi assert len(wf.mi_p[0].shape) != 0 # don't compute permutations nor stats wf = WfMi('cc', 'ffx', verbose=False) mi, pv = wf.fit(dt, mcp=None, **kw_mi) assert wf.mi_p[0].shape == (0, ) assert pv.min() == pv.max() == 1. # don't compute permutations twice wf = WfMi('cc', 'ffx', verbose=False) t_start_1 = tst() wf.fit(dt, mcp='fdr', **kw_mi) t_end_1 = tst() t_start_2 = tst() wf.fit(dt, mcp='maxstat', **kw_mi) t_end_2 = tst() assert t_end_1 - t_start_1 > t_end_2 - t_start_2
def test_definition(self): """Test workflow definition.""" y, gt = sim_mi_cc(x, snr=1.) dt = DatasetEphy(x, y, roi, times=time) wf = WfMi(mi_type='cc', inference='rfx') wf.fit(dt, **kw_mi) wf.tvalues
def test_properties(self): ds = DatasetEphy(x, roi=roi, times=times) wf = WfConnComod() wf.fit(ds, **kw_conn) assert isinstance(wf.mi, list) assert isinstance(wf.mi_p, list) assert all([k.shape == (n_subjects, n_times) for k in wf.mi]) assert all([k.shape == (n_perm, n_subjects, n_times) for k in wf.mi_p])
def test_conjunction_analysis(self): """Test the conjunction analysis.""" y, gt = sim_mi_cc(x, snr=1.) dt = DatasetEphy(x, y, roi, times=time) wf = WfMi(mi_type='cc', inference='rfx') mi, pv = wf.fit(dt, **kw_mi) cj_ss, cj = wf.conjunction_analysis(dt) assert cj_ss.shape == (n_subjects, n_times, n_roi) assert cj.shape == (n_times, n_roi)
def test_properties(self): """Test function properties.""" d_3d = self._get_data(3) ds = DatasetEphy(d_3d, y='y', z='z', roi='roi', times='times', **kw) assert isinstance(ds.x, list) assert isinstance(ds.df_rs, pd.DataFrame) np.testing.assert_array_equal(ds.times, times) np.testing.assert_array_equal(ds.roi_names, ['roi_0', 'roi_1', 'roi_2', 'roi_3'])
def test_mi_ccd(self): """Test method fit.""" # built the regressor and discret variables y, z, gt = sim_mi_ccd(x, snr=1.) # run workflow for mi_meth in ['gc', 'bin']: dt = DatasetEphy(x, y, roi, z=z, times=time) WfMi(mi_type='ccd', inference='ffx', mi_method=mi_meth, verbose=False).fit(dt, **kw_mi) WfMi(mi_type='ccd', inference='rfx', mi_method=mi_meth, verbose=False).fit(dt, **kw_mi)
def test_mi_ccd(self): """Test method fit.""" # built the regressor and discret variables y, z, gt = sim_mi_ccd(x.copy(), snr=1.) # run workflow dt = DatasetEphy(x.copy(), y=y, roi=roi, z=z, times=time) for est in est_list: estimator = est(mi_type='ccd') WfMi(mi_type='ccd', inference='ffx', estimator=estimator, verbose=False).fit(dt, **kw_mi) WfMi(mi_type='ccd', inference='rfx', estimator=estimator, verbose=False).fit(dt, **kw_mi)
def test_agg_ch(self): """Test channels aggregation.""" # build dataset (with aggregation) d_3d = self._get_data(3) ds = DatasetEphy(d_3d, roi='roi', agg_ch=True, **kw) ds_roi2 = ds.get_roi_data("roi_0", copnorm=False) np.testing.assert_array_equal(ds_roi2['agg_ch'].data, [0] * 30) # build dataset (without aggregation) ds = DatasetEphy(d_3d, roi='roi', agg_ch=False, **kw) ds_roi0 = ds.get_roi_data("roi_0", copnorm=False) np.testing.assert_array_equal(ds_roi0['agg_ch'].data, [0] * 10 + [1] * 10 + [6] * 10)
def test_slicing(self): """Test spatio-temporal slicing.""" d_3d = self._get_data(3) xt1, xt2 = 0.1, 0.5 xs1, xs2 = np.abs(times - xt1).argmin(), np.abs(times - xt2).argmin() # ds.sel ds = DatasetEphy(d_3d, times='times', **kw) ds = ds.sel(times=slice(xt1, xt2)) np.testing.assert_array_equal(ds.times, times[slice(xs1, xs2 + 1)]) # ds.isel ds = DatasetEphy(d_3d, times='times', **kw) ds = ds.isel(times=slice(xs1, xs2)) np.testing.assert_array_equal(ds.times, times[slice(xs1, xs2)])
def test_multivariate(self): """Test multivariate""" d_4d = self._get_data(4) # multivariate = False ds = DatasetEphy(d_4d, roi='roi', multivariate=False, **kw) x_roi2 = ds.get_roi_data('roi_2') assert x_roi2.dims == ('freqs', 'times', 'mv', 'rtr') assert x_roi2.shape == (4, 100, 1, 20) # multivariate = True d_4d = self._get_data(4) ds = DatasetEphy(d_4d, roi='roi', multivariate=True, **kw) x_roi2 = ds.get_roi_data('roi_2') assert x_roi2.dims == ('times', 'mv', 'rtr') assert x_roi2.shape == (100, 4, 20)
def test_definition(self): """Test function definition.""" d_3d = self._get_data(3) DatasetEphy(d_3d.copy(), **kw) DatasetEphy(d_3d.copy(), y='y', **kw) DatasetEphy(d_3d.copy(), y='y', z='z', **kw) DatasetEphy(d_3d.copy(), y='y', z='z', roi='roi', **kw) DatasetEphy(d_3d.copy(), y='y', z='z', roi='roi', times='times', **kw) DatasetEphy(d_3d.copy(), y='y', z='z', roi='roi', times='times', agg_ch=False, **kw) DatasetEphy(d_3d, y='y', z='z', roi='roi', times='times', agg_ch=False, multivariate=True, **kw)
def test_copnorm(self): """Test function copnorm.""" # build dataset d_3d = self._get_data(3) ds = DatasetEphy(d_3d, y='y', z='z', **kw) # check copnorm range ds_roi2 = ds.get_roi_data("roi_2", copnorm=False) s1_r2, s2_r2 = d_3d[0].sel(roi='roi_2'), d_3d[1].sel(roi='roi_2') s12 = xr.concat((s1_r2, s2_r2), 'trials').T.expand_dims('mv', axis=-2) assert 9. < ds_roi2.data.ravel().mean() < 11. np.testing.assert_array_equal(s12.data, ds_roi2.data) ds_roi2 = ds.get_roi_data("roi_2", copnorm=True) assert -1. < ds_roi2.data.ravel().mean() < 1. # check values (gcrn_per_suj=False) gc_t = ds.get_roi_data("roi_2", copnorm=True, gcrn_per_suj=False) np.testing.assert_array_equal(copnorm_nd(s12.data), gc_t.data) # check values (gcrn_per_suj=True) gc_t = ds.get_roi_data("roi_2", copnorm=True, gcrn_per_suj=True) np.testing.assert_array_equal( copnorm_cat_nd(s12.data, gc_t['subject'].data), gc_t.data)
# Load network feature feature = xr.load_dataarray(path_metric) # Average if needed out = average_stages(feature, avg) # Convert to format required by the MI workflow coh += [out.isel(roi=[r]) for r in range(len(out['roi']))] stim += [out.attrs["stim"].astype(int)] \ * len(out['roi']) del feature ############################################################################### # MI Workflow ############################################################################### # Convert to DatasetEphy dt = DatasetEphy(coh, y=stim, nb_min_suj=10, times="times", roi="roi") mi_type = 'cd' inference = 'rfx' kernel = None if avg: mcp = "fdr" else: mcp = "cluster" estimator = GCMIEstimator(mi_type='cd', copnorm=True, biascorrect=True, demeaned=False, tensor=True,
dims=('epochs', 'channels', 'times'), coords=(epochs, ch[k], times)) # finally, replace it in the original list x_xr.append(arr_xr) print(x_xr[0]) ############################################################################### # Build the dataset # ----------------- # # Finally, we pass the data to the :class:`frites.dataset.DatasetEphy` class # in order to create the dataset # here, we specify to the DatasetEphy class that the roi dimension is actually # called 'channels' in the DataArray and the times dimension is called 'times' dt = DatasetEphy(x_xr, roi='channels', times='times') print(dt) print('Time vector : ', dt.times) print('ROI (first subject) : ', dt.roi[0]) ############################################################################### # MultiIndex support # ------------------ # # DataArray also supports multi-indexing of a single dimension. # create a continuous regressor (prediction error, delta P etc.) dp = np.random.uniform(-1, 1, (n_epochs, )) # create a discret variable (e.g experimental conditions) cond = np.array([0] * 5 + [1] * 5)
# electrophysiological data and your discret variable, you are looking for # recording sites and time-points of data that correlates with conditions. This # kind of analysis is similar to what is done in machine-learning. First, # extract the conditions from the random dataset generated above. x, y, _ = sim_mi_cd(x, snr=1., n_conditions=3) # print the conditions for the single subject print(y[0]) ############################################################################### # Define the electrophysiological dataset # --------------------------------------- # # Now we define an instance of :class:`frites.dataset.DatasetEphy` dt = DatasetEphy(x, y=y, roi=roi, times=time) ############################################################################### # Compute the mutual information # ------------------------------ # # Once we have the dataset instance, we can then define an instance of workflow # :class:`frites.workflow.WfMi`. This instance is used to compute the mutual # information # mutual information type ('cd' = continuous / discret) mi_type = 'cd' # define the workflow wf = WfMi(mi_type=mi_type, verbose=False) # compute the mutual information
sl = slice(40, 60) y = [x[k][..., sl].mean(axis=(1, 2)) for k in range(len(x))] ############################################################################### # .. note:: # Taking the mean across time points and space is exactly the behavior of # the function :func:`frites.simulations.sim_mi_cc` ############################################################################### # Define the electrophysiological dataset # --------------------------------------- # # Now we define an instance of :class:`frites.dataset.DatasetEphy` dt = DatasetEphy(x, y, roi) ############################################################################### # Compute the mutual information # ------------------------------ # # Once we have the dataset instance, we can then define an instance of workflow # :class:`frites.workflow.WfMi`. This instance is used to compute the mutual # information # mutual information type ('cc' = continuous / continuous) mi_type = 'cc' # define the workflow wf = WfMi(mi_type, inference='ffx') # compute the mutual information without permutations
# # Bellow, we start by simulating some distant correlations by injecting the # activity of an ROI to another for k in range(n_subjects): x[k][:, [1], slice(20, 40)] += x[k][:, [0], slice(20, 40)] x[k][:, [2], slice(60, 80)] += x[k][:, [3], slice(60, 80)] print(f'Corr 1 : {roi[0][0]}-{roi[0][1]} between [{times[20]}-{times[40]}]') print(f'Corr 2 : {roi[0][2]}-{roi[0][3]} between [{times[60]}-{times[80]}]') ############################################################################### # Define the electrophysiological dataset # --------------------------------------- # # Now we define an instance of :class:`frites.dataset.DatasetEphy` dt = DatasetEphy(x, roi=roi, times=times) ############################################################################### # Compute the pairwise connectivity # --------------------------------- # # Once we have the dataset instance, we can then define an instance of workflow # :class:`frites.workflow.WfComod`. This instance is then used to compute the # pairwise connectivity n_perm = 100 # number of permutations to compute kernel = np.hanning(10) # used for smoothing the MI wf = WfComod(kernel=kernel) mi, pv = wf.fit(dt, n_perm=n_perm, n_jobs=1) print(mi)
def test_fit(self): ds = DatasetEphy(x, roi=roi, times=times) WfConnComod().fit(ds, **kw_conn)
# Load network feature feature = xr.load_dataarray(path_metric) # Average if needed out = average_stages(feature, avg) # Convert to format required by the MI workflow coh += [out.isel(roi=[r]) for r in range(len(out['roi']))] stim += [out.attrs["stim"].astype(int)] \ * len(out['roi']) del feature ############################################################################### # MI Workflow ############################################################################### # Convert to DatasetEphy dt = DatasetEphy(sxx, y=coh, z=stim, nb_min_suj=10, times="times", roi="roi") mi_type = 'ccd' inference = 'rfx' kernel = None estimator = GCMIEstimator(mi_type=mi_type, relative=False, copnorm=True, biascorrect=False, demeaned=False, tensor=True, gpu=False, verbose=None) wf = WfMi(mi_type, inference, verbose=True, kernel=kernel, estimator=estimator) kw = dict(n_jobs=20, n_perm=100)
# simulate multiple subjects and build the dataset container x, y, roi = [], [], [] times = np.linspace(-1, 1, n_times) freqs = np.linspace(60, 160, n_freqs) for s, tr in zip(range(n_subjects), n_trials): # simulate the data coming from a single subject x_single_suj, y_single_suj = sim_single_subject(n_freqs, n_times, tr) # xarray conversion _x = xr.DataArray(x_single_suj, dims=('trials', 'roi', 'freqs', 'times'), coords=(y_single_suj, ['roi_0'], freqs, times)) x += [_x] # define an instance of DatasetEphy ds = DatasetEphy(x, y='trials', roi='roi', times='times') ############################################################################### # Compute the mutual information ############################################################################### # Then we compute the quantity of information shared by the time-frequency data # and the continuous regressor # compute the mutual information wf = WfMi(inference='ffx', mi_type='cc') mi, pv = wf.fit(ds, n_perm=200, mcp='cluster', random_state=0, n_jobs=1) ############################################################################### # plot the mutual information and p-values plt.figure(figsize=(10, 4))
# generate some random channel names ch_suj = np.array([f"ch_{r}" for r in range(n_channels)]) # concatenate in a list x.append(x_suj) ch.append(ch_suj) # finally lets create a time vector times = np.arange(n_times) / sf ############################################################################### # Create the dataset # ------------------ # # The creation of the dataset is performed using the class # :class:`frites.dataset.DatasetEphy` dt = DatasetEphy(x.copy(), roi=ch, times=times) print(dt) plt.plot(dt.times, dt.x[0][:, 0, :].T) plt.xlabel('Times') plt.title('Electrophysiological data of the first subject, for the first ' 'channel') plt.show() ############################################################################### # Data smoothing # -------------- # # If you have MNE-Python installed, you can also smooth the data using # :class:`frites.dataset.DatasetEphy.savgol_filter`. One important thing is # that operations are performed inplace, which means that once launched, the
def test_nb_min_suj(self): """Test if the selection based on a minimum number of subjects.""" d_3d = self._get_data(3) roi = [['r2', 'r1', 'r0', 'r3', 'r4'], ['r0', 'r1', 'r5', 'r6', 'r7']] # nb_min_suj = -inf ds = DatasetEphy(d_3d, roi=roi, nb_min_suj=None, **kw) assert len(ds.roi_names) == 8 ds.get_connectivity_pairs(directed=False, as_blocks=True)[0] df = ds.get_connectivity_pairs(directed=False)[0] assert len(df) == 19 ds.get_connectivity_pairs(directed=True, as_blocks=True)[0] df = ds.get_connectivity_pairs(directed=True)[0] assert len(df) == 38 # nb_min_suj = 2 ds = DatasetEphy(d_3d, roi=roi, nb_min_suj=2, **kw) assert len(ds.roi_names) == 2 ds.get_connectivity_pairs(directed=False, as_blocks=True)[0] df = ds.get_connectivity_pairs(directed=False)[0] assert len(df) == 1 ds.get_connectivity_pairs(directed=True, as_blocks=True)[0] df = ds.get_connectivity_pairs(directed=True)[0] assert len(df) == 2
# initialize subject's data with random noise _x = np.random.rand(n_trials, 2, n_times) # normal continuous regressor _y = np.random.normal(size=(n_trials, )) # first contact has positive correlations _x[:, 0, slice(30, 70)] += _y.reshape(-1, 1) # second contact has negative correlations _x[:, 1, slice(30, 70)] -= _y.reshape(-1, 1) x += [_x] y += [_y] roi += [np.array(['roi_0', 'roi_0'])] # now, compute the mi with default parameters ds = DatasetEphy(x, y=y, roi=roi, times=times, agg_ch=True) mi = WfMi(mi_type='cc').fit(ds, mcp='noperm')[0] # compute the mi at the contact level ds = DatasetEphy(x, y=y, roi=roi, times=times, agg_ch=False) mi_c = WfMi(mi_type='ccd').fit(ds, mcp='noperm')[0] # plot the comparison plt.figure() plt.plot(times, mi, label="MI across contacts") plt.plot(times, mi_c, label="MI at the contact level") plt.legend() plt.title('I(C; C)') plt.show() ###############################################################################
def test_savgol_filter(self): """Test function savgol_filter.""" d_3d = self._get_data(3) ds = DatasetEphy(d_3d, times='times', **kw) ds.savgol_filter(10., verbose=False)
def test_builtin(self): """Test function builtin.""" d_3d = self._get_data(3) ds = DatasetEphy(d_3d, y='y', z='z', **kw)
# Once the data have been created, we simulate an increase of mutual # information by creating a continuous variable `y` using the function # :func:`frites.simulations.sim_mi_cc`. This allows to simulate model-based # analysis by computing $I(data; y)$ where `data` and `y` are two continuous # variables y, _ = sim_mi_cc(data, snr=.1) ############################################################################### # Create an electrophysiological dataset # -------------------------------------- # # Now, we use the :class:`frites.dataset.DatasetEphy` in order to create a # compatible electrophysiological dataset dt = DatasetEphy(data, y, roi=roi, times=time, verbose=False) ############################################################################### # Define the workflow # ------------------- # # We now define the workflow for computing mi and evaluate statistics using the # class :class:`frites.workflow.WfMi`. Here, the type of mutual # information to perform is 'cc' between it's computed between two continuous # variables. And we also specify the inference type 'ffx' for fixed-effect mi_type = 'cc' inference = 'ffx' kernel = np.hanning(10) wf = WfMi(mi_type, inference, verbose=False, kernel=kernel)