Esempio n. 1
0
def test_joblib_cache():
    from joblib import hash, Memory
    mask = np.zeros((40, 40, 40))
    mask[20, 20, 20] = 1
    mask_img = Nifti1Image(mask, np.eye(4))

    with testing.write_tmp_imgs(mask_img, create_files=True) as filename:
        masker = NiftiMasker(mask_img=filename)
        masker.fit()
        mask_hash = hash(masker.mask_img_)
        get_data(masker.mask_img_)
        assert mask_hash == hash(masker.mask_img_)

        # Test a tricky issue with memmapped joblib.memory that makes
        # imgs return by inverse_transform impossible to save
        cachedir = mkdtemp()
        try:
            masker.memory = Memory(location=cachedir, mmap_mode='r', verbose=0)
            X = masker.transform(mask_img)
            # inverse_transform a first time, so that the result is cached
            out_img = masker.inverse_transform(X)
            out_img = masker.inverse_transform(X)
            out_img.to_filename(os.path.join(cachedir, 'test.nii'))
        finally:
            # enables to delete "filename" on windows
            del masker
            shutil.rmtree(cachedir, ignore_errors=True)
Esempio n. 2
0
def test_masking_first_level_model():
    """
    Checks that using NiftiMasker when instantiating
    FirstLevelModel doesn't raise Error when calling
    generate_report().
    """
    with InTemporaryDirectory():
        shapes, rk = ((7, 8, 7, 15), (7, 8, 7, 16)), 3
        mask, fmri_data, design_matrices =\
            write_fake_fmri_data_and_design(shapes, rk)
        masker = NiftiMasker(mask_img=mask)
        masker.fit(fmri_data)
        flm = FirstLevelModel(mask_img=masker).fit(
            fmri_data, design_matrices=design_matrices
        )
        contrast = np.eye(3)[1]

        report_flm = flm.generate_report(
            contrast, plot_type='glass', height_control=None,
            min_distance=15, alpha=0.001, threshold=2.78
        )

        report_iframe = report_flm.get_iframe()
        # So flake8 doesn't complain about not using variable (F841)
        report_iframe

        del mask, flm, fmri_data, masker
Esempio n. 3
0
def test_overlaid_report(data_img_3d):
    pytest.importorskip('matplotlib')

    masker = NiftiMasker(target_affine=np.eye(3) * 8)
    html = masker.generate_report()
    assert "Please `fit` the object" in str(html)
    masker.fit(data_img_3d)
    html = masker.generate_report()
    assert '<div class="overlay">' in str(html)
Esempio n. 4
0
def test_with_files():
    # Standard masking
    data = np.zeros((40, 40, 40, 2))
    data[20, 20, 20] = 1
    data_img = Nifti1Image(data, np.eye(4))

    with testing.write_tmp_imgs(data_img) as filename:
        masker = NiftiMasker()
        masker.fit(filename)
        masker.transform(filename)
Esempio n. 5
0
def test_mask_strategy_errors():
    # Error with unknown mask_strategy
    mask = NiftiMasker(mask_strategy='oops')
    with pytest.raises(ValueError,
                       match="Unknown value of mask_strategy 'oops'"):
        mask.fit()
    # Warning with deprecated 'template' strategy
    img = np.random.RandomState(42).uniform(size=(9, 9, 5))
    img = Nifti1Image(img, np.eye(4))
    mask = NiftiMasker(mask_strategy='template')
    with pytest.warns(UserWarning,
                      match="Masking strategy 'template' is deprecated."):
        mask.fit(img)
Esempio n. 6
0
def test_5d():
    mask = np.zeros((10, 10, 10))
    mask[3:7, 3:7, 3:7] = 1
    mask_img = Nifti1Image(mask, np.eye(4))

    # Test that, in list of 4d images with last dimension=1, they are
    # considered as 3d

    rng = np.random.RandomState(42)
    data_5d = [rng.random_sample((10, 10, 10, 3)) for i in range(5)]
    data_5d = [nibabel.Nifti1Image(d, np.eye(4)) for d in data_5d]

    masker = NiftiMasker(mask_img=mask_img)
    masker.fit()
    with pytest.raises(DimensionError,
                       match="Input data has incompatible dimensionality: "
                       "Expected dimension is 4D and you provided "
                       "a list of 4D images \\(5D\\)."):
        masker.transform(data_5d)
Esempio n. 7
0
def test_4d_single_scan():
    mask = np.zeros((10, 10, 10))
    mask[3:7, 3:7, 3:7] = 1
    mask_img = Nifti1Image(mask, np.eye(4))

    # Test that, in list of 4d images with last dimension=1, they are
    # considered as 3d

    rng = np.random.RandomState(42)
    data_5d = [rng.random_sample((10, 10, 10, 1)) for i in range(5)]
    data_4d = [d[..., 0] for d in data_5d]
    data_5d = [nibabel.Nifti1Image(d, np.eye(4)) for d in data_5d]
    data_4d = [nibabel.Nifti1Image(d, np.eye(4)) for d in data_4d]

    masker = NiftiMasker(mask_img=mask_img)
    masker.fit()
    data_trans_5d = masker.transform(data_5d)
    data_trans_4d = masker.transform(data_4d)

    assert_array_equal(data_trans_4d, data_trans_5d)
Esempio n. 8
0
def test_auto_mask():
    # This mostly a smoke test
    data = np.zeros((9, 9, 9))
    data[3:-3, 3:-3, 3:-3] = 10
    img = Nifti1Image(data, np.eye(4))
    masker = NiftiMasker()
    # Smoke test the fit
    masker.fit(img)
    # Smoke test the transform
    # With a 4D img
    masker.transform([
        img,
    ])
    # With a 3D img
    masker.transform(img)

    # check exception when transform() called without prior fit()
    masker2 = NiftiMasker(mask_img=img)
    with pytest.raises(ValueError, match='has not been fitted. '):
        masker2.transform(img)
Esempio n. 9
0
def test_nan():
    data = np.ones((9, 9, 9))
    data[0] = np.nan
    data[:, 0] = np.nan
    data[:, :, 0] = np.nan
    data[-1] = np.nan
    data[:, -1] = np.nan
    data[:, :, -1] = np.nan
    data[3:-3, 3:-3, 3:-3] = 10
    img = Nifti1Image(data, np.eye(4))
    masker = NiftiMasker(mask_args=dict(opening=0))
    masker.fit(img)
    mask = get_data(masker.mask_img_)
    assert mask[1:-1, 1:-1, 1:-1].all()
    assert not mask[0].any()
    assert not mask[:, 0].any()
    assert not mask[:, :, 0].any()
    assert not mask[-1].any()
    assert not mask[:, -1].any()
    assert not mask[:, :, -1].any()
Esempio n. 10
0
def test_high_level_glm_one_session():
    shapes, rk = [(7, 8, 9, 15)], 3
    mask, fmri_data, design_matrices =\
        generate_fake_fmri_data_and_design(shapes, rk)

    # Give an unfitted NiftiMasker as mask_img and check that we get an error
    masker = NiftiMasker(mask)
    with pytest.raises(ValueError,
                       match="It seems that NiftiMasker has not been fitted."):
        FirstLevelModel(mask_img=masker).fit(
            fmri_data[0], design_matrices=design_matrices[0])

    # Give a fitted NiftiMasker with a None mask_img_ attribute
    # and check that the masker parameters are overridden by the
    # FirstLevelModel parameters
    masker.fit()
    masker.mask_img_ = None
    with pytest.warns(UserWarning,
                      match="Parameter memory of the masker overridden"):
        FirstLevelModel(mask_img=masker).fit(
            fmri_data[0], design_matrices=design_matrices[0])

    # Give a fitted NiftiMasker
    masker = NiftiMasker(mask)
    masker.fit()
    single_session_model = FirstLevelModel(mask_img=masker).fit(
        fmri_data[0], design_matrices=design_matrices[0])
    assert single_session_model.masker_ == masker

    # Call with verbose (improve coverage)
    single_session_model = FirstLevelModel(mask_img=None, verbose=1).fit(
        fmri_data[0], design_matrices=design_matrices[0])

    single_session_model = FirstLevelModel(mask_img=None).fit(
        fmri_data[0], design_matrices=design_matrices[0])
    assert isinstance(single_session_model.masker_.mask_img_, Nifti1Image)

    single_session_model = FirstLevelModel(mask_img=mask).fit(
        fmri_data[0], design_matrices=design_matrices[0])
    z1 = single_session_model.compute_contrast(np.eye(rk)[:1])
    assert isinstance(z1, Nifti1Image)
Esempio n. 11
0
def test_4d_reports(mask):
    # Dummy 4D data
    data = np.zeros((10, 10, 10, 3), dtype=int)
    data[..., 0] = 1
    data[..., 1] = 2
    data[..., 2] = 3
    data_img_4d = Nifti1Image(data, np.eye(4))

    # test .fit method
    masker = NiftiMasker(mask_strategy='epi')
    masker.fit(data_img_4d)
    assert masker._report_content['warning_message'] is None
    html = masker.generate_report()
    _check_html(html)

    # test .fit_transform method
    masker = NiftiMasker(mask_img=mask, standardize=True)
    masker.fit_transform(data_img_4d)
    assert masker._report_content['warning_message'] is None
    html = masker.generate_report()
    _check_html(html)
Esempio n. 12
0
def test_matrix_orientation():
    """Test if processing is performed along the correct axis."""

    # the "step" kind generate heavyside-like signals for each voxel.
    # all signals being identical, standardizing along the wrong axis
    # would leave a null signal. Along the correct axis, the step remains.
    fmri, mask = data_gen.generate_fake_fmri(shape=(40, 41, 42), kind="step")
    masker = NiftiMasker(mask_img=mask, standardize=True, detrend=True)
    timeseries = masker.fit_transform(fmri)
    assert (timeseries.shape[0] == fmri.shape[3])
    assert (timeseries.shape[1] == get_data(mask).sum())
    std = timeseries.std(axis=0)
    assert (std.shape[0] == timeseries.shape[1])  # paranoid
    assert (not np.any(std < 0.1))

    # Test inverse transform
    masker = NiftiMasker(mask_img=mask, standardize=False, detrend=False)
    masker.fit()
    timeseries = masker.transform(fmri)
    recovered = masker.inverse_transform(timeseries)
    np.testing.assert_array_almost_equal(get_data(recovered), get_data(fmri))
Esempio n. 13
0
def test_compute_epi_mask():
    # Taken from test_masking.py, but used to test that the masker class
    #   is passing parameters appropriately.
    mean_image = np.ones((9, 9, 3))
    mean_image[3:-2, 3:-2, :] = 10
    mean_image[5, 5, :] = 11
    mean_image = Nifti1Image(mean_image.astype(float), np.eye(4))

    masker = NiftiMasker(mask_strategy='epi', mask_args=dict(opening=False))
    masker.fit(mean_image)
    mask1 = masker.mask_img_

    masker2 = NiftiMasker(mask_strategy='epi',
                          mask_args=dict(opening=False, exclude_zeros=True))
    masker2.fit(mean_image)
    mask2 = masker2.mask_img_

    # With an array with no zeros, exclude_zeros should not make
    # any difference
    np.testing.assert_array_equal(get_data(mask1), get_data(mask2))

    # Check that padding with zeros does not change the extracted mask
    mean_image2 = np.zeros((30, 30, 3))
    mean_image2[3:12, 3:12, :] = get_data(mean_image)
    mean_image2 = Nifti1Image(mean_image2, np.eye(4))

    masker3 = NiftiMasker(mask_strategy='epi',
                          mask_args=dict(opening=False, exclude_zeros=True))
    masker3.fit(mean_image2)
    mask3 = masker3.mask_img_
    np.testing.assert_array_equal(get_data(mask1), get_data(mask3)[3:12, 3:12])

    # However, without exclude_zeros, it does
    masker4 = NiftiMasker(mask_strategy='epi', mask_args=dict(opening=False))
    masker4.fit(mean_image2)
    mask4 = masker4.mask_img_

    assert not np.allclose(get_data(mask1), get_data(mask4)[3:12, 3:12])
Esempio n. 14
0
def test_mask_4d():
    # Dummy mask
    mask = np.zeros((10, 10, 10), dtype=int)
    mask[3:7, 3:7, 3:7] = 1
    mask_bool = mask.astype(bool)
    mask_img = Nifti1Image(mask, np.eye(4))

    # Dummy data
    data = np.zeros((10, 10, 10, 5), dtype=int)
    data[..., 0] = 1
    data[..., 1] = 2
    data[..., 2] = 3
    data_img_4d = Nifti1Image(data, np.eye(4))
    data_imgs = [
        index_img(data_img_4d, 0),
        index_img(data_img_4d, 1),
        index_img(data_img_4d, 2)
    ]

    # check whether transform is indeed selecting niimgs subset
    sample_mask = np.array([0, 2])
    masker = NiftiMasker(mask_img=mask_img)
    masker.fit()
    data_trans = masker.transform(data_imgs, sample_mask=sample_mask)
    data_trans_img = index_img(data_img_4d, sample_mask)
    data_trans_direct = get_data(data_trans_img)[mask_bool, :]
    data_trans_direct = np.swapaxes(data_trans_direct, 0, 1)
    assert_array_equal(data_trans, data_trans_direct)

    masker = NiftiMasker(mask_img=mask_img)
    masker.fit()
    data_trans2 = masker.transform(data_img_4d, sample_mask=sample_mask)
    assert_array_equal(data_trans2, data_trans_direct)

    diff_sample_mask = np.array([2, 4])
    data_trans_img_diff = index_img(data_img_4d, diff_sample_mask)
    data_trans_direct_diff = get_data(data_trans_img_diff)[mask_bool, :]
    data_trans_direct_diff = np.swapaxes(data_trans_direct_diff, 0, 1)
    masker = NiftiMasker(mask_img=mask_img)
    masker.fit()
    data_trans3 = masker.transform(data_img_4d, sample_mask=diff_sample_mask)
    assert_array_equal(data_trans3, data_trans_direct_diff)
Esempio n. 15
0
def non_parametric_inference(second_level_input,
                             confounds=None,
                             design_matrix=None,
                             second_level_contrast=None,
                             first_level_contrast=None,
                             mask=None,
                             smoothing_fwhm=None,
                             model_intercept=True,
                             n_perm=10000,
                             two_sided_test=False,
                             random_state=None,
                             n_jobs=1,
                             verbose=0):
    """Generate p-values corresponding to the contrasts provided
    based on permutation testing. This function reuses the 'permuted_ols'
    function Nilearn.

    Parameters
    ----------
    second_level_input : pandas DataFrame or list of Niimg-like objects.

        If a pandas DataFrame, then they have to contain subject_label,
        map_name and effects_map_path. It can contain multiple maps that
        would be selected during contrast estimation with the argument
        first_level_contrast of the compute_contrast function. The
        DataFrame will be sorted based on the subject_label column to avoid
        order inconsistencies when extracting the maps. So the rows of the
        automatically computed design matrix, if not provided, will
        correspond to the sorted subject_label column.

        If list of Niimg-like objects then this is taken literally as Y
        for the model fit and design_matrix must be provided.

    confounds : pandas DataFrame, optional
        Must contain a subject_label column. All other columns are
        considered as confounds and included in the model. If
        design_matrix is provided then this argument is ignored.
        The resulting second level design matrix uses the same column
        names as in the given DataFrame for confounds. At least two columns
        are expected, "subject_label" and at least one confound.

    design_matrix : pandas DataFrame, optional
        Design matrix to fit the GLM. The number of rows
        in the design matrix must agree with the number of maps derived
        from second_level_input.
        Ensure that the order of maps given by a second_level_input
        list of Niimgs matches the order of the rows in the design matrix.

    second_level_contrast : str or array of shape (n_col), optional
        Where ``n_col`` is the number of columns of the design matrix.
        The default (None) is accepted if the design matrix has a single
        column, in which case the only possible contrast array((1)) is
        applied; when the design matrix has multiple columns, an error is
        raised.

    first_level_contrast : str, optional
        In case a pandas DataFrame was provided as second_level_input this
        is the map name to extract from the pandas dataframe map_name column.
        It has to be a 't' contrast.

        .. versionadded:: 0.8.2

    mask : Niimg-like, NiftiMasker or MultiNiftiMasker object, optional
        Mask to be used on data. If an instance of masker is passed,
        then its mask will be used. If no mask is given,
        it will be computed automatically by a MultiNiftiMasker with default
        parameters. Automatic mask computation assumes first level imgs have
        already been masked.
    %(smoothing_fwhm)s
    model_intercept : bool, optional
      If True, a constant column is added to the confounding variates
      unless the tested variate is already the intercept.
      Default=True.

    n_perm : int, optional
      Number of permutations to perform.
      Permutations are costly but the more are performed, the more precision
      one gets in the p-values estimation. Default=10000.

    two_sided_test : boolean, optional
      If True, performs an unsigned t-test. Both positive and negative
      effects are considered; the null hypothesis is that the effect is zero.
      If False, only positive effects are considered as relevant. The null
      hypothesis is that the effect is zero or negative.
      Default=False.

    random_state : int or None, optional
      Seed for random number generator, to have the same permutations
      in each computing units.

    n_jobs : int, optional
      Number of parallel workers.
      If -1 is provided, all CPUs are used.
      A negative number indicates that all the CPUs except (abs(n_jobs) - 1)
      ones will be used. Default=1.

    verbose : int, optional
        Verbosity level (0 means no message). Default=0.

    Returns
    -------
    neg_log_corrected_pvals_img : Nifti1Image
        The image which contains negative logarithm of the
        corrected p-values.

    """
    _check_second_level_input(second_level_input,
                              design_matrix,
                              flm_object=False,
                              df_object=True)
    _check_confounds(confounds)
    _check_design_matrix(design_matrix)

    if isinstance(second_level_input, pd.DataFrame):
        second_level_input = _sort_input_dataframe(second_level_input)
    sample_map, _ = _process_second_level_input(second_level_input)
    # Report progress
    t0 = time.time()
    if verbose > 0:
        sys.stderr.write("Fitting second level model...")

    # Learn the mask. Assume the first level imgs have been masked.
    if not isinstance(mask, NiftiMasker):
        masker = NiftiMasker(mask_img=mask,
                             smoothing_fwhm=smoothing_fwhm,
                             memory=Memory(None),
                             verbose=max(0, verbose - 1),
                             memory_level=1)
    else:
        masker = clone(mask)
        if smoothing_fwhm is not None:
            if getattr(masker, 'smoothing_fwhm') is not None:
                warn('Parameter smoothing_fwhm of the masker overridden')
                setattr(masker, 'smoothing_fwhm', smoothing_fwhm)
    masker.fit(sample_map)

    # Report progress
    if verbose > 0:
        sys.stderr.write("\nComputation of second level model done in "
                         "%i seconds\n" % (time.time() - t0))

    # Check and obtain the contrast
    contrast = _get_contrast(second_level_contrast, design_matrix)
    # Get effect_maps
    effect_maps = _infer_effect_maps(second_level_input, first_level_contrast)

    # Check design matrix and effect maps agree on number of rows
    _check_effect_maps(effect_maps, design_matrix)

    # Obtain tested_var
    if contrast in design_matrix.columns.tolist():
        tested_var = np.asarray(design_matrix[contrast])

    # Mask data
    target_vars = masker.transform(effect_maps)

    # Perform massively univariate analysis with permuted OLS
    neg_log_pvals_permuted_ols, _, _ = permuted_ols(
        tested_var,
        target_vars,
        model_intercept=model_intercept,
        n_perm=n_perm,
        two_sided_test=two_sided_test,
        random_state=random_state,
        n_jobs=n_jobs,
        verbose=max(0, verbose - 1))
    neg_log_corrected_pvals_img = masker.inverse_transform(
        np.ravel(neg_log_pvals_permuted_ols))

    return neg_log_corrected_pvals_img
# print basic information on the dataset
print('First functional nifti image (4D) is at: %s' % func_filename)

###########################################################################
# Compute the mask
from nilearn.maskers import NiftiMasker

# As this is raw movie watching based EPI, the background is noisy and we
# cannot rely on the 'background' masking strategy. We need to use the 'epi'
# one
nifti_masker = NiftiMasker(standardize=True,
                           mask_strategy='epi',
                           memory="nilearn_cache",
                           memory_level=2,
                           smoothing_fwhm=8)
nifti_masker.fit(func_filename)
mask_img = nifti_masker.mask_img_

###########################################################################
# Visualize the mask using the plot_roi method
from nilearn.plotting import plot_roi
from nilearn.image.image import mean_img

# calculate mean image for the background
mean_func_img = mean_img(func_filename)

plot_roi(mask_img, mean_func_img, display_mode='y', cut_coords=4, title="Mask")

###########################################################################
# Visualize the mask using the 'generate_report' method
# This report can be displayed in a Jupyter Notebook,
Esempio n. 17
0
class FirstLevelModel(BaseGLM):
    """ Implementation of the General Linear Model
    for single session fMRI data.

    Parameters
    ----------
    t_r : float
        This parameter indicates repetition times of the experimental runs.
        In seconds. It is necessary to correctly consider times in the design
        matrix. This parameter is also passed to :func:`nilearn.signal.clean`.
        Please see the related documentation for details.

    slice_time_ref : float, optional
        This parameter indicates the time of the reference slice used in the
        slice timing preprocessing step of the experimental runs. It is
        expressed as a percentage of the t_r (time repetition), so it can have
        values between 0. and 1. Default=0.
    %(hrf_model)s
        Default='glover'.
    drift_model : string, optional
        This parameter specifies the desired drift model for the design
        matrices. It can be 'polynomial', 'cosine' or None.
        Default='cosine'.

    high_pass : float, optional
        This parameter specifies the cut frequency of the high-pass filter in
        Hz for the design matrices. Used only if drift_model is 'cosine'.
        Default=0.01.

    drift_order : int, optional
        This parameter specifies the order of the drift model (in case it is
        polynomial) for the design matrices. Default=1.

    fir_delays : array of shape(n_onsets) or list, optional
        In case of FIR design, yields the array of delays used in the FIR
        model, in scans. Default=[0].

    min_onset : float, optional
        This parameter specifies the minimal onset relative to the design
        (in seconds). Events that start before (slice_time_ref * t_r +
        min_onset) are not considered. Default=-24.

    mask_img : Niimg-like, NiftiMasker object or False, optional
        Mask to be used on data. If an instance of masker is passed,
        then its mask will be used. If no mask is given,
        it will be computed automatically by a NiftiMasker with default
        parameters. If False is given then the data will not be masked.

    target_affine : 3x3 or 4x4 matrix, optional
        This parameter is passed to nilearn.image.resample_img.
        Please see the related documentation for details.

    target_shape : 3-tuple of integers, optional
        This parameter is passed to nilearn.image.resample_img.
        Please see the related documentation for details.
    %(smoothing_fwhm)s
    memory : string, optional
        Path to the directory used to cache the masking process and the glm
        fit. By default, no caching is done.
        Creates instance of joblib.Memory.

    memory_level : integer, optional
        Rough estimator of the amount of memory used by caching. Higher value
        means more memory for caching.

    standardize : boolean, optional
        If standardize is True, the time-series are centered and normed:
        their variance is put to 1 in the time dimension. Default=False.

    signal_scaling : False, int or (int, int), optional
        If not False, fMRI signals are
        scaled to the mean value of scaling_axis given,
        which can be 0, 1 or (0, 1).
        0 refers to mean scaling each voxel with respect to time,
        1 refers to mean scaling each time point with respect to all voxels &
        (0, 1) refers to scaling with respect to voxels and time,
        which is known as grand mean scaling.
        Incompatible with standardize (standardize=False is enforced when
        signal_scaling is not False).
        Default=0.

    noise_model : {'ar1', 'ols'}, optional
        The temporal variance model. Default='ar1'.

    verbose : integer, optional
        Indicate the level of verbosity. By default, nothing is printed.
        If 0 prints nothing. If 1 prints progress by computation of
        each run. If 2 prints timing details of masker and GLM. If 3
        prints masker computation details. Default=0.

    n_jobs : integer, optional
        The number of CPUs to use to do the computation. -1 means
        'all CPUs', -2 'all CPUs but one', and so on.
        Default=1.

    minimize_memory : boolean, optional
        Gets rid of some variables on the model fit results that are not
        necessary for contrast computation and would only be useful for
        further inspection of model details. This has an important impact
        on memory consumption. Default=True.

    subject_label : string, optional
        This id will be used to identify a `FirstLevelModel` when passed to
        a `SecondLevelModel` object.

    Attributes
    ----------
    labels_ : array of shape (n_voxels,),
        a map of values on voxels used to identify the corresponding model

    results_ : dict,
        with keys corresponding to the different labels values.
        Values are SimpleRegressionResults corresponding to the voxels,
        if minimize_memory is True,
        RegressionResults if minimize_memory is False

    Notes
    -----
    This class is experimental.
    It may change in any future release of Nilearn.

    """
    def __init__(self, t_r=None, slice_time_ref=0., hrf_model='glover',
                 drift_model='cosine', high_pass=.01, drift_order=1,
                 fir_delays=[0], min_onset=-24, mask_img=None,
                 target_affine=None, target_shape=None, smoothing_fwhm=None,
                 memory=Memory(None), memory_level=1, standardize=False,
                 signal_scaling=0, noise_model='ar1', verbose=0, n_jobs=1,
                 minimize_memory=True, subject_label=None):
        # design matrix parameters
        self.t_r = t_r
        self.slice_time_ref = slice_time_ref
        self.hrf_model = hrf_model
        self.drift_model = drift_model
        self.high_pass = high_pass
        self.drift_order = drift_order
        self.fir_delays = fir_delays
        self.min_onset = min_onset
        # glm parameters
        self.mask_img = mask_img
        self.target_affine = target_affine
        self.target_shape = target_shape
        self.smoothing_fwhm = smoothing_fwhm
        if isinstance(memory, str):
            self.memory = Memory(memory)
        else:
            self.memory = memory
        self.memory_level = memory_level
        self.standardize = standardize
        if signal_scaling is False:
            self.signal_scaling = signal_scaling
        elif signal_scaling in [0, 1, (0, 1)]:
            self.signal_scaling = signal_scaling
            self.standardize = False
        else:
            raise ValueError('signal_scaling must be "False", "0", "1"'
                             ' or "(0, 1)"')

        self.noise_model = noise_model
        self.verbose = verbose
        self.n_jobs = n_jobs
        self.minimize_memory = minimize_memory
        # attributes
        self.labels_ = None
        self.results_ = None
        self.subject_label = subject_label

    @property
    def scaling_axis(self):
        warn(DeprecationWarning(
            "Deprecated. `scaling_axis` will be removed in 0.11.0. "
            "Please use `signal_scaling` instead."
        ))
        return self.signal_scaling

    def fit(self, run_imgs, events=None, confounds=None, sample_masks=None,
            design_matrices=None, bins=100):
        """Fit the GLM

        For each run:
        1. create design matrix X
        2. do a masker job: fMRI_data -> Y
        3. fit regression to (Y, X)

        Parameters
        ----------
        run_imgs : Niimg-like object or list of Niimg-like objects,
            Data on which the GLM will be fitted. If this is a list,
            the affine is considered the same for all.

        events : pandas Dataframe or string or list of pandas DataFrames \
                 or strings, optional
            fMRI events used to build design matrices. One events object
            expected per run_img. Ignored in case designs is not None.
            If string, then a path to a csv file is expected.

        confounds : pandas Dataframe, numpy array or string or
            list of pandas DataFrames, numpy arrays or strings, optional
            Each column in a DataFrame corresponds to a confound variable
            to be included in the regression model of the respective run_img.
            The number of rows must match the number of volumes in the
            respective run_img. Ignored in case designs is not None.
            If string, then a path to a csv file is expected.

        sample_masks : array_like, or list of array_like, optional
            shape of array: (number of scans - number of volumes removed, )
            Indices of retained volumes. Masks the niimgs along time/fourth
            dimension to perform scrubbing (remove volumes with high motion)
            and/or remove non-steady-state volumes.
            Default=None.

            .. versionadded:: 0.9.2.dev

        design_matrices : pandas DataFrame or \
                          list of pandas DataFrames, optional
            Design matrices that will be used to fit the GLM. If given it
            takes precedence over events and confounds.

        bins : int, optional
            Maximum number of discrete bins for the AR coef histogram.
            If an autoregressive model with order greater than one is specified
            then adaptive quantification is performed and the coefficients
            will be clustered via K-means with `bins` number of clusters.
            Default=100.

        """
        # Initialize masker_ to None such that attribute exists
        self.masker_ = None

        # Raise a warning if both design_matrices and confounds are provided
        if design_matrices is not None and \
                (confounds is not None or events is not None):
            warn(
                'If design matrices are supplied, '
                'confounds and events will be ignored.'
            )
        # Local import to prevent circular imports
        from nilearn.maskers import NiftiMasker  # noqa

        # Check arguments
        # Check imgs type
        if events is not None:
            _check_events_file_uses_tab_separators(events_files=events)
        if not isinstance(run_imgs, (list, tuple)):
            run_imgs = [run_imgs]
        if design_matrices is None:
            if events is None:
                raise ValueError('events or design matrices must be provided')
            if self.t_r is None:
                raise ValueError('t_r not given to FirstLevelModel object'
                                 ' to compute design from events')
        else:
            design_matrices = _check_run_tables(run_imgs, design_matrices,
                                                'design_matrices')
        # Check that number of events and confound files match number of runs
        # Also check that events and confound files can be loaded as DataFrame
        if events is not None:
            events = _check_run_tables(run_imgs, events, 'events')
        if confounds is not None:
            confounds = _check_run_tables(run_imgs, confounds, 'confounds')

        if sample_masks is not None:
            sample_masks = _check_run_sample_masks(len(run_imgs), sample_masks)

        # Learn the mask
        if self.mask_img is False:
            # We create a dummy mask to preserve functionality of api
            ref_img = check_niimg(run_imgs[0])
            self.mask_img = Nifti1Image(np.ones(ref_img.shape[:3]),
                                        ref_img.affine)
        if not isinstance(self.mask_img, NiftiMasker):
            self.masker_ = NiftiMasker(mask_img=self.mask_img,
                                       smoothing_fwhm=self.smoothing_fwhm,
                                       target_affine=self.target_affine,
                                       standardize=self.standardize,
                                       mask_strategy='epi',
                                       t_r=self.t_r,
                                       memory=self.memory,
                                       verbose=max(0, self.verbose - 2),
                                       target_shape=self.target_shape,
                                       memory_level=self.memory_level
                                       )
            self.masker_.fit(run_imgs[0])
        else:
            # Make sure masker has been fitted otherwise no attribute mask_img_
            self.mask_img._check_fitted()
            if self.mask_img.mask_img_ is None and self.masker_ is None:
                self.masker_ = clone(self.mask_img)
                for param_name in ['target_affine', 'target_shape',
                                   'smoothing_fwhm', 't_r', 'memory',
                                   'memory_level']:
                    our_param = getattr(self, param_name)
                    if our_param is None:
                        continue
                    if getattr(self.masker_, param_name) is not None:
                        warn('Parameter %s of the masker'
                             ' overridden' % param_name)
                    setattr(self.masker_, param_name, our_param)
                self.masker_.fit(run_imgs[0])
            else:
                self.masker_ = self.mask_img

        # For each run fit the model and keep only the regression results.
        self.labels_, self.results_, self.design_matrices_ = [], [], []
        n_runs = len(run_imgs)
        t0 = time.time()
        for run_idx, run_img in enumerate(run_imgs):
            # Report progress
            if self.verbose > 0:
                percent = float(run_idx) / n_runs
                percent = round(percent * 100, 2)
                dt = time.time() - t0
                # We use a max to avoid a division by zero
                if run_idx == 0:
                    remaining = 'go take a coffee, a big one'
                else:
                    remaining = (100. - percent) / max(0.01, percent) * dt
                    remaining = '%i seconds remaining' % remaining

                sys.stderr.write(
                    "Computing run %d out of %d runs (%s)\n"
                    % (run_idx + 1, n_runs, remaining))

            # Build the experimental design for the glm
            run_img = check_niimg(run_img, ensure_ndim=4)
            if design_matrices is None:
                n_scans = get_data(run_img).shape[3]
                if confounds is not None:
                    confounds_matrix = confounds[run_idx].values
                    if confounds_matrix.shape[0] != n_scans:
                        raise ValueError('Rows in confounds does not match'
                                         'n_scans in run_img at index %d'
                                         % (run_idx,))
                    confounds_names = confounds[run_idx].columns.tolist()
                else:
                    confounds_matrix = None
                    confounds_names = None
                start_time = self.slice_time_ref * self.t_r
                end_time = (n_scans - 1 + self.slice_time_ref) * self.t_r
                frame_times = np.linspace(start_time, end_time, n_scans)
                design = make_first_level_design_matrix(frame_times,
                                                        events[run_idx],
                                                        self.hrf_model,
                                                        self.drift_model,
                                                        self.high_pass,
                                                        self.drift_order,
                                                        self.fir_delays,
                                                        confounds_matrix,
                                                        confounds_names,
                                                        self.min_onset
                                                        )
            else:
                design = design_matrices[run_idx]

            if sample_masks is not None:
                sample_mask = sample_masks[run_idx]
                design = design.iloc[sample_mask, :]
            else:
                sample_mask = None

            self.design_matrices_.append(design)

            # Mask and prepare data for GLM
            if self.verbose > 1:
                t_masking = time.time()
                sys.stderr.write('Starting masker computation \r')

            Y = self.masker_.transform(run_img, sample_mask=sample_mask)
            del run_img  # Delete unmasked image to save memory

            if self.verbose > 1:
                t_masking = time.time() - t_masking
                sys.stderr.write('Masker took %d seconds       \n'
                                 % t_masking)

            if self.signal_scaling is not False:  # noqa
                Y, _ = mean_scaling(Y, self.signal_scaling)
            if self.memory:
                mem_glm = self.memory.cache(run_glm, ignore=['n_jobs'])
            else:
                mem_glm = run_glm

            # compute GLM
            if self.verbose > 1:
                t_glm = time.time()
                sys.stderr.write('Performing GLM computation\r')
            labels, results = mem_glm(Y, design.values,
                                      noise_model=self.noise_model,
                                      bins=bins, n_jobs=self.n_jobs)
            if self.verbose > 1:
                t_glm = time.time() - t_glm
                sys.stderr.write('GLM took %d seconds         \n' % t_glm)

            self.labels_.append(labels)
            # We save memory if inspecting model details is not necessary
            if self.minimize_memory:
                for key in results:
                    results[key] = SimpleRegressionResults(results[key])
            self.results_.append(results)
            del Y

        # Report progress
        if self.verbose > 0:
            sys.stderr.write("\nComputation of %d runs done in %i seconds\n\n"
                             % (n_runs, time.time() - t0))
        return self

    def compute_contrast(self, contrast_def, stat_type=None,
                         output_type='z_score'):
        """Generate different outputs corresponding to
        the contrasts provided e.g. z_map, t_map, effects and variance.
        In multi-session case, outputs the fixed effects map.

        Parameters
        ----------
        contrast_def : str or array of shape (n_col) or list of (string or
                       array of shape (n_col))

            where ``n_col`` is the number of columns of the design matrix,
            (one array per run). If only one array is provided when there
            are several runs, it will be assumed that the same contrast is
            desired for all runs. The string can be a formula compatible with
            `pandas.DataFrame.eval`. Basically one can use the name of the
            conditions as they appear in the design matrix of the fitted model
            combined with operators +- and combined with numbers
            with operators +-`*`/.

        stat_type : {'t', 'F'}, optional
            Type of the contrast.

        output_type : str, optional
            Type of the output map. Can be 'z_score', 'stat', 'p_value',
            'effect_size', 'effect_variance' or 'all'.
            Default='z_score'.

        Returns
        -------
        output : Nifti1Image or dict
            The desired output image(s). If ``output_type == 'all'``, then
            the output is a dictionary of images, keyed by the type of image.

        """
        if self.labels_ is None or self.results_ is None:
            raise ValueError('The model has not been fit yet')

        if isinstance(contrast_def, (np.ndarray, str)):
            con_vals = [contrast_def]
        elif isinstance(contrast_def, (list, tuple)):
            con_vals = contrast_def
        else:
            raise ValueError('contrast_def must be an array or str or list of'
                             ' (array or str)')

        n_runs = len(self.labels_)
        n_contrasts = len(con_vals)
        if n_contrasts == 1 and n_runs > 1:
            warn('One contrast given, assuming it for all %d runs' % n_runs)
            con_vals = con_vals * n_runs
        elif n_contrasts != n_runs:
            raise ValueError('%d contrasts given, while there are %d runs' %
                             (n_contrasts, n_runs))

        # Translate formulas to vectors
        for cidx, (con, design_mat) in enumerate(zip(con_vals,
                                                     self.design_matrices_)
                                                 ):
            design_columns = design_mat.columns.tolist()
            if isinstance(con, str):
                con_vals[cidx] = expression_to_contrast_vector(
                    con, design_columns)

        valid_types = ['z_score', 'stat', 'p_value', 'effect_size',
                       'effect_variance']
        valid_types.append('all')  # ensuring 'all' is the final entry.
        if output_type not in valid_types:
            raise ValueError(
                'output_type must be one of {}'.format(valid_types))
        contrast = _compute_fixed_effect_contrast(self.labels_, self.results_,
                                                  con_vals, stat_type)
        output_types = (valid_types[:-1]
                        if output_type == 'all' else [output_type])
        outputs = {}
        for output_type_ in output_types:
            estimate_ = getattr(contrast, output_type_)()
            # Prepare the returned images
            output = self.masker_.inverse_transform(estimate_)
            contrast_name = str(con_vals)
            output.header['descrip'] = (
                '%s of contrast %s' % (output_type_, contrast_name))
            outputs[output_type_] = output

        return outputs if output_type == 'all' else output

    def _get_voxelwise_model_attribute(self, attribute,
                                       result_as_time_series):
        """Transform RegressionResults instances within a dictionary
        (whose keys represent the autoregressive coefficient under the 'ar1'
        noise model or only 0.0 under 'ols' noise_model and values are the
        RegressionResults instances) into input nifti space.

        Parameters
        ----------
        attribute : str
            an attribute of a RegressionResults instance.
            possible values include: residuals, normalized_residuals,
            predicted, SSE, r_square, MSE.

        result_as_time_series : bool
            whether the RegressionResult attribute has a value
            per timepoint of the input nifti image.

        Returns
        -------
        output : list
            A list of Nifti1Image(s).

        """
        # check if valid attribute is being accessed.
        all_attributes = dict(vars(RegressionResults)).keys()
        possible_attributes = [prop
                               for prop in all_attributes
                               if '__' not in prop
                               ]
        if attribute not in possible_attributes:
            msg = ("attribute must be one of: "
                   "{attr}".format(attr=possible_attributes)
                   )
            raise ValueError(msg)

        if self.minimize_memory:
            raise ValueError(
                'To access voxelwise attributes like '
                'R-squared, residuals, and predictions, '
                'the `FirstLevelModel`-object needs to store '
                'there attributes. '
                'To do so, set `minimize_memory` to `False` '
                'when initializing the `FirstLevelModel`-object.')

        if self.labels_ is None or self.results_ is None:
            raise ValueError('The model has not been fit yet')

        output = []

        for design_matrix, labels, results in zip(self.design_matrices_,
                                                  self.labels_,
                                                  self.results_
                                                  ):
            if result_as_time_series:
                voxelwise_attribute = np.zeros((design_matrix.shape[0],
                                                len(labels))
                                               )
            else:
                voxelwise_attribute = np.zeros((1, len(labels)))

            for label_ in results:
                label_mask = labels == label_
                voxelwise_attribute[:, label_mask] = getattr(results[label_],
                                                             attribute)

            output.append(self.masker_.inverse_transform(voxelwise_attribute))

        return output
Esempio n. 18
0
def non_parametric_inference(
    second_level_input,
    confounds=None,
    design_matrix=None,
    second_level_contrast=None,
    first_level_contrast=None,
    mask=None,
    smoothing_fwhm=None,
    model_intercept=True,
    n_perm=10000,
    two_sided_test=False,
    random_state=None,
    n_jobs=1,
    verbose=0,
    threshold=None,
):
    """Generate p-values corresponding to the contrasts provided
    based on permutation testing.

    This function is a light wrapper around
    :func:`~nilearn.mass_univariate.permuted_ols`, with additional steps to
    ensure compatibility with the :mod:`~nilearn.glm.second_level` module.

    Parameters
    ----------
    second_level_input : :obj:`pandas.DataFrame` or :obj:`list` of Niimg-like \
            objects
        If a pandas DataFrame, then they have to contain subject_label,
        map_name and effects_map_path. It can contain multiple maps that
        would be selected during contrast estimation with the argument
        first_level_contrast of the compute_contrast function. The
        DataFrame will be sorted based on the subject_label column to avoid
        order inconsistencies when extracting the maps. So the rows of the
        automatically computed design matrix, if not provided, will
        correspond to the sorted subject_label column.

        If list of Niimg-like objects then this is taken literally as Y
        for the model fit and design_matrix must be provided.

    confounds : :obj:`pandas.DataFrame`, optional
        Must contain a subject_label column. All other columns are
        considered as confounds and included in the model. If
        design_matrix is provided then this argument is ignored.
        The resulting second level design matrix uses the same column
        names as in the given DataFrame for confounds. At least two columns
        are expected, "subject_label" and at least one confound.

    design_matrix : :obj:`pandas.DataFrame`, optional
        Design matrix to fit the GLM. The number of rows
        in the design matrix must agree with the number of maps derived
        from second_level_input.
        Ensure that the order of maps given by a second_level_input
        list of Niimgs matches the order of the rows in the design matrix.

    second_level_contrast : :obj:`str` or array of shape (n_col), optional
        Where ``n_col`` is the number of columns of the design matrix.
        The default (None) is accepted if the design matrix has a single
        column, in which case the only possible contrast array((1)) is
        applied; when the design matrix has multiple columns, an error is
        raised.

    first_level_contrast : :obj:`str`, optional
        In case a pandas DataFrame was provided as second_level_input this
        is the map name to extract from the pandas dataframe map_name column.
        It has to be a 't' contrast.

        .. versionadded:: 0.9.0

    mask : Niimg-like, :obj:`~nilearn.maskers.NiftiMasker` or \
            :obj:`~nilearn.maskers.MultiNiftiMasker` object, optional
        Mask to be used on data. If an instance of masker is passed,
        then its mask will be used. If no mask is given,
        it will be computed automatically by a MultiNiftiMasker with default
        parameters. Automatic mask computation assumes first level imgs have
        already been masked.
    %(smoothing_fwhm)s
    model_intercept : :obj:`bool`, optional
        If True, a constant column is added to the confounding variates
        unless the tested variate is already the intercept.
        Default=True.

    n_perm : :obj:`int`, optional
        Number of permutations to perform.
        Permutations are costly but the more are performed, the more precision
        one gets in the p-values estimation. Default=10000.

    two_sided_test : :obj:`bool`, optional
        If True, performs an unsigned t-test. Both positive and negative
        effects are considered; the null hypothesis is that the effect is zero.
        If False, only positive effects are considered as relevant. The null
        hypothesis is that the effect is zero or negative.
        Default=False.

    random_state : :obj:`int` or None, optional
        Seed for random number generator, to have the same permutations
        in each computing units.

    n_jobs : :obj:`int`, optional
        Number of parallel workers.
        If -1 is provided, all CPUs are used.
        A negative number indicates that all the CPUs except (abs(n_jobs) - 1)
        ones will be used. Default=1.

    verbose : :obj:`int`, optional
        Verbosity level (0 means no message). Default=0.

    threshold : None or :obj:`float`, optional
        Cluster-forming threshold in p-scale.
        This is only used for cluster-level inference.
        If None, no cluster-level inference will be performed.
        Default=None.

        .. warning::

            Performing cluster-level inference will increase the computation
            time of the permutation procedure.

        .. versionadded:: 0.9.2.dev

    Returns
    -------
    neg_log10_vfwe_pvals_img : :class:`~nibabel.nifti1.Nifti1Image`
        The image which contains negative logarithm of the
        voxel-level FWER-corrected p-values.

        .. note::
            This is returned if ``threshold`` is None (the default).

    outputs : :obj:`dict`
        Output images, organized in a dictionary.
        Each image is 3D/4D, with the potential fourth dimension corresponding
        to the regressors.

        .. note::
            This is returned if ``threshold`` is not None.

        .. versionadded:: 0.9.2.dev

        Here are the keys:

        =============== =======================================================
        key             description
        =============== =======================================================
        t               T-statistics associated with the significance test of
                        the n_regressors explanatory variates against the
                        n_descriptors target variates.
        logp_max_t      Negative log10 family-wise error rate-corrected
                        p-values corrected based on the distribution of maximum
                        t-statistics from permutations.
        logp_max_size   Negative log10 family-wise error rate-corrected
                        p-values corrected based on the distribution of maximum
                        cluster sizes from permutations.
                        This map is generated through cluster-level methods, so
                        the values in the map describe the significance of
                        clusters, rather than individual voxels.

                        Returned only if ``threshold`` is not None.
        logp_max_mass   Negative log10 family-wise error rate-corrected
                        p-values corrected based on the distribution of maximum
                        cluster masses from permutations.
                        This map is generated through cluster-level methods, so
                        the values in the map describe the significance of
                        clusters, rather than individual voxels.

                        Returned only if ``threshold`` is not None.
        ============= =======================================================

    """
    _check_second_level_input(second_level_input,
                              design_matrix,
                              flm_object=False,
                              df_object=True)
    _check_confounds(confounds)
    _check_design_matrix(design_matrix)

    if isinstance(second_level_input, pd.DataFrame):
        second_level_input = _sort_input_dataframe(second_level_input)
    sample_map, _ = _process_second_level_input(second_level_input)

    # Report progress
    t0 = time.time()
    if verbose > 0:
        sys.stderr.write("Fitting second level model...")

    # Learn the mask. Assume the first level imgs have been masked.
    if not isinstance(mask, NiftiMasker):
        masker = NiftiMasker(mask_img=mask,
                             smoothing_fwhm=smoothing_fwhm,
                             memory=Memory(None),
                             verbose=max(0, verbose - 1),
                             memory_level=1)

    else:
        masker = clone(mask)
        if smoothing_fwhm is not None:
            if getattr(masker, 'smoothing_fwhm') is not None:
                warn('Parameter smoothing_fwhm of the masker overridden')
                setattr(masker, 'smoothing_fwhm', smoothing_fwhm)

    masker.fit(sample_map)

    # Report progress
    if verbose > 0:
        sys.stderr.write("\nComputation of second level model done in "
                         "%i seconds\n" % (time.time() - t0))

    # Check and obtain the contrast
    contrast = _get_contrast(second_level_contrast, design_matrix)

    # Get effect_maps
    effect_maps = _infer_effect_maps(second_level_input, first_level_contrast)

    # Check design matrix and effect maps agree on number of rows
    _check_effect_maps(effect_maps, design_matrix)

    # Obtain tested_var
    if contrast in design_matrix.columns.tolist():
        tested_var = np.asarray(design_matrix[contrast])

    # Mask data
    target_vars = masker.transform(effect_maps)

    # Perform massively univariate analysis with permuted OLS
    outputs = permuted_ols(
        tested_var,
        target_vars,
        model_intercept=model_intercept,
        n_perm=n_perm,
        two_sided_test=two_sided_test,
        random_state=random_state,
        n_jobs=n_jobs,
        verbose=max(0, verbose - 1),
        masker=masker,
        threshold=threshold,
        output_type='dict',
    )
    neg_log10_vfwe_pvals = outputs['logp_max_t']
    neg_log10_vfwe_pvals_img = masker.inverse_transform(
        np.ravel(neg_log10_vfwe_pvals), )

    if threshold is not None:
        # Original t-statistics
        t_img = masker.inverse_transform(np.ravel(outputs['t']))

        # Cluster size-based p-values
        neg_log10_csfwe_pvals_img = masker.inverse_transform(
            np.ravel(outputs['logp_max_size']), )

        # Cluster mass-based p-values
        neg_log10_cmfwe_pvals_img = masker.inverse_transform(
            np.ravel(outputs['logp_max_mass']), )

        out = {
            't': t_img,
            'logp_max_t': neg_log10_vfwe_pvals_img,
            'logp_max_size': neg_log10_csfwe_pvals_img,
            'logp_max_mass': neg_log10_cmfwe_pvals_img,
        }
        return out
    else:
        return neg_log10_vfwe_pvals_img
Esempio n. 19
0
class SecondLevelModel(BaseGLM):
    """ Implementation of the General Linear Model for multiple subject
    fMRI data

    Parameters
    ----------
    mask_img : Niimg-like, NiftiMasker or MultiNiftiMasker object, optional
        Mask to be used on data. If an instance of masker is passed,
        then its mask will be used. If no mask is given,
        it will be computed automatically by a MultiNiftiMasker with default
        parameters. Automatic mask computation assumes first level imgs have
        already been masked.

    target_affine : 3x3 or 4x4 matrix, optional
        This parameter is passed to :func:`nilearn.image.resample_img`.
        Please see the related documentation for details.

    target_shape : 3-tuple of integers, optional
        This parameter is passed to :func:`nilearn.image.resample_img`.
        Please see the related documentation for details.
    %(smoothing_fwhm)s
    memory : string, optional
        Path to the directory used to cache the masking process and the glm
        fit. By default, no caching is done. Creates instance of joblib.Memory.

    memory_level : integer, optional
        Rough estimator of the amount of memory used by caching. Higher value
        means more memory for caching. Default=1.

    verbose : integer, optional
        Indicate the level of verbosity. By default, nothing is printed.
        If 0 prints nothing. If 1 prints final computation time.
        If 2 prints masker computation details. Default=0.

    n_jobs : integer, optional
        The number of CPUs to use to do the computation. -1 means
        'all CPUs', -2 'all CPUs but one', and so on.
        Default=1.

    minimize_memory : boolean, optional
        Gets rid of some variables on the model fit results that are not
        necessary for contrast computation and would only be useful for
        further inspection of model details. This has an important impact
        on memory consumption. Default=True.

    Notes
    -----
    This class is experimental.
    It may change in any future release of Nilearn.

    """
    def __init__(self,
                 mask_img=None,
                 target_affine=None,
                 target_shape=None,
                 smoothing_fwhm=None,
                 memory=Memory(None),
                 memory_level=1,
                 verbose=0,
                 n_jobs=1,
                 minimize_memory=True):
        self.mask_img = mask_img
        self.target_affine = target_affine
        self.target_shape = target_shape
        self.smoothing_fwhm = smoothing_fwhm
        if isinstance(memory, str):
            self.memory = Memory(memory)
        else:
            self.memory = memory
        self.memory_level = memory_level
        self.verbose = verbose
        self.n_jobs = n_jobs
        self.minimize_memory = minimize_memory
        self.second_level_input_ = None
        self.confounds_ = None
        self.labels_ = None
        self.results_ = None

    def fit(self, second_level_input, confounds=None, design_matrix=None):
        """ Fit the second-level GLM

        1. create design matrix
        2. do a masker job: fMRI_data -> Y
        3. fit regression to (Y, X)

        Parameters
        ----------
        second_level_input: list of `FirstLevelModel` objects or pandas
                            DataFrame or list of Niimg-like objects.

            Giving FirstLevelModel objects will allow to easily compute
            the second level contrast of arbitrary first level contrasts thanks
            to the first_level_contrast argument of the compute_contrast
            method. Effect size images will be computed for each model to
            contrast at the second level.

            If a pandas DataFrame, then they have to contain subject_label,
            map_name and effects_map_path. It can contain multiple maps that
            would be selected during contrast estimation with the argument
            first_level_contrast of the compute_contrast function. The
            DataFrame will be sorted based on the subject_label column to avoid
            order inconsistencies when extracting the maps. So the rows of the
            automatically computed design matrix, if not provided, will
            correspond to the sorted subject_label column.

            If list of Niimg-like objects then this is taken literally as Y
            for the model fit and design_matrix must be provided.

        confounds : pandas DataFrame, optional
            Must contain a subject_label column. All other columns are
            considered as confounds and included in the model. If
            design_matrix is provided then this argument is ignored.
            The resulting second level design matrix uses the same column
            names as in the given DataFrame for confounds. At least two columns
            are expected, "subject_label" and at least one confound.

        design_matrix : pandas DataFrame, optional
            Design matrix to fit the GLM. The number of rows
            in the design matrix must agree with the number of maps derived
            from second_level_input.
            Ensure that the order of maps given by a second_level_input
            list of Niimgs matches the order of the rows in the design matrix.

        """
        # check second_level_input
        _check_second_level_input(second_level_input,
                                  design_matrix,
                                  confounds=confounds)

        # check confounds
        _check_confounds(confounds)

        # check design matrix
        _check_design_matrix(design_matrix)

        if isinstance(second_level_input, pd.DataFrame):
            second_level_input = _sort_input_dataframe(second_level_input)
        self.second_level_input_ = second_level_input
        self.confounds_ = confounds
        sample_map, subjects_label = _process_second_level_input(
            second_level_input)

        # Report progress
        t0 = time.time()
        if self.verbose > 0:
            sys.stderr.write("Fitting second level model. "
                             "Take a deep breath\r")

        # Create and set design matrix, if not given
        if design_matrix is None:
            design_matrix = make_second_level_design_matrix(
                subjects_label, confounds)
        self.design_matrix_ = design_matrix

        # Learn the mask. Assume the first level imgs have been masked.
        if not isinstance(self.mask_img, NiftiMasker):
            self.masker_ = NiftiMasker(mask_img=self.mask_img,
                                       target_affine=self.target_affine,
                                       target_shape=self.target_shape,
                                       smoothing_fwhm=self.smoothing_fwhm,
                                       memory=self.memory,
                                       verbose=max(0, self.verbose - 1),
                                       memory_level=self.memory_level)
        else:
            self.masker_ = clone(self.mask_img)
            for param_name in ['smoothing_fwhm', 'memory', 'memory_level']:
                our_param = getattr(self, param_name)
                if our_param is None:
                    continue
                if getattr(self.masker_, param_name) is not None:
                    warn('Parameter %s of the masker overridden' % param_name)
                setattr(self.masker_, param_name, our_param)
        self.masker_.fit(sample_map)

        # Report progress
        if self.verbose > 0:
            sys.stderr.write("\nComputation of second level model done in "
                             "%i seconds\n" % (time.time() - t0))

        return self

    def compute_contrast(self,
                         second_level_contrast=None,
                         first_level_contrast=None,
                         second_level_stat_type=None,
                         output_type='z_score'):
        """Generate different outputs corresponding to
        the contrasts provided e.g. z_map, t_map, effects and variance.

        Parameters
        ----------
        second_level_contrast : str or array of shape (n_col), optional
            Where ``n_col`` is the number of columns of the design matrix. The
            string can be a formula compatible with `pandas.DataFrame.eval`.
            Basically one can use the name of the conditions as they appear in
            the design matrix of the fitted model combined with operators +-
            and combined with numbers with operators +-`*`/. The default (None)
            is accepted if the design matrix has a single column, in which case
            the only possible contrast array((1)) is applied; when the design
            matrix has multiple columns, an error is raised.

        first_level_contrast : str or array of shape (n_col) with respect to
                               FirstLevelModel, optional

            In case a list of FirstLevelModel was provided as
            second_level_input, we have to provide a contrast to apply to
            the first level models to get the corresponding list of images
            desired, that would be tested at the second level. In case a
            pandas DataFrame was provided as second_level_input this is the
            map name to extract from the pandas dataframe map_name column.
            It has to be a 't' contrast.

        second_level_stat_type : {'t', 'F'}, optional
            Type of the second level contrast

        output_type : str, optional
            Type of the output map. Can be 'z_score', 'stat', 'p_value',
            'effect_size', 'effect_variance' or 'all'.
            Default='z-score'.

        Returns
        -------
        output_image : Nifti1Image
            The desired output image(s). If ``output_type == 'all'``, then
            the output is a dictionary of images, keyed by the type of image.

        """
        if self.second_level_input_ is None:
            raise ValueError('The model has not been fit yet')

        # check first_level_contrast
        _check_first_level_contrast(self.second_level_input_,
                                    first_level_contrast)

        # check contrast and obtain con_val
        con_val = _get_con_val(second_level_contrast, self.design_matrix_)

        # check output type
        # 'all' is assumed to be the final entry;
        # if adding more, place before 'all'
        valid_types = [
            'z_score', 'stat', 'p_value', 'effect_size', 'effect_variance',
            'all'
        ]
        _check_output_type(output_type, valid_types)

        # Get effect_maps appropriate for chosen contrast
        effect_maps = _infer_effect_maps(self.second_level_input_,
                                         first_level_contrast)
        # Check design matrix X and effect maps Y agree on number of rows
        _check_effect_maps(effect_maps, self.design_matrix_)

        # Fit an Ordinary Least Squares regression for parametric statistics
        Y = self.masker_.transform(effect_maps)
        if self.memory:
            mem_glm = self.memory.cache(run_glm, ignore=['n_jobs'])
        else:
            mem_glm = run_glm
        labels, results = mem_glm(Y,
                                  self.design_matrix_.values,
                                  n_jobs=self.n_jobs,
                                  noise_model='ols')

        # We save memory if inspecting model details is not necessary
        if self.minimize_memory:
            for key in results:
                results[key] = SimpleRegressionResults(results[key])
        self.labels_ = labels
        self.results_ = results

        # We compute contrast object
        if self.memory:
            mem_contrast = self.memory.cache(compute_contrast)
        else:
            mem_contrast = compute_contrast
        contrast = mem_contrast(self.labels_, self.results_, con_val,
                                second_level_stat_type)

        output_types = \
            valid_types[:-1] if output_type == 'all' else [output_type]

        outputs = {}
        for output_type_ in output_types:
            # We get desired output from contrast object
            estimate_ = getattr(contrast, output_type_)()
            # Prepare the returned images
            output = self.masker_.inverse_transform(estimate_)
            contrast_name = str(con_val)
            output.header['descrip'] = ('%s of contrast %s' %
                                        (output_type, contrast_name))
            outputs[output_type_] = output

        return outputs if output_type == 'all' else output

    def _get_voxelwise_model_attribute(self, attribute, result_as_time_series):
        """Transform RegressionResults instances within a dictionary
        (whose keys represent the autoregressive coefficient under the 'ar1'
        noise model or only 0.0 under 'ols' noise_model and values are the
        RegressionResults instances) into input nifti space.

        Parameters
        ----------
        attribute : str
            an attribute of a RegressionResults instance.
            possible values include: 'residuals', 'normalized_residuals',
            'predicted', SSE, r_square, MSE.

        result_as_time_series : bool
            whether the RegressionResult attribute has a value
            per timepoint of the input nifti image.

        Returns
        -------
        output : list
            A list of Nifti1Image(s).

        """
        # check if valid attribute is being accessed.
        all_attributes = dict(vars(RegressionResults)).keys()
        possible_attributes = [
            prop for prop in all_attributes if '__' not in prop
        ]
        if attribute not in possible_attributes:
            msg = ("attribute must be one of: "
                   "{attr}".format(attr=possible_attributes))
            raise ValueError(msg)

        if self.minimize_memory:
            raise ValueError(
                'To access voxelwise attributes like '
                'R-squared, residuals, and predictions, '
                'the `SecondLevelModel`-object needs to store '
                'there attributes. '
                'To do so, set `minimize_memory` to `False` '
                'when initializing the `SecondLevelModel`-object.')

        if self.labels_ is None or self.results_ is None:
            raise ValueError("The model has no results. This could be "
                             "because the model has not been fitted yet "
                             "or because no contrast has been computed "
                             "already.")

        if result_as_time_series:
            voxelwise_attribute = np.zeros(
                (self.design_matrix_.shape[0], len(self.labels_)))
        else:
            voxelwise_attribute = np.zeros((1, len(self.labels_)))

        for label_ in self.results_:
            label_mask = self.labels_ == label_
            voxelwise_attribute[:,
                                label_mask] = getattr(self.results_[label_],
                                                      attribute)
        return self.masker_.inverse_transform(voxelwise_attribute)
Esempio n. 20
0

######################################################################
# Reshape and mask images
# -----------------------

print("\nReshaping and masking images.\n")

with warnings.catch_warnings():
    warnings.simplefilter('ignore', UserWarning)
    warnings.simplefilter('ignore', DeprecationWarning)

    mask_img = load_mni152_brain_mask()
    masker = NiftiMasker(
        mask_img=mask_img, memory='nilearn_cache', memory_level=1)
    masker = masker.fit()

    # Images may fail to be transformed, and are of different shapes,
    # so we need to transform one-by-one and keep track of failures.
    X = []
    is_usable = np.ones((len(images),), dtype=bool)

    for index, image_path in enumerate(images):
        # load image and remove nan and inf values.
        # applying smooth_img to an image with fwhm=None simply cleans up
        # non-finite values but otherwise doesn't modify the image.
        image = smooth_img(image_path, fwhm=None)
        try:
            X.append(masker.transform(image))
        except Exception as e:
            meta = nv_data['images_meta'][index]
# Load Miyawaki dataset
from nilearn import datasets
miyawaki_dataset = datasets.fetch_miyawaki2008()

# print basic information on the dataset
print('First functional nifti image (4D) is located at: %s' %
      miyawaki_dataset.func[0])  # 4D data

miyawaki_filename = miyawaki_dataset.func[0]
miyawaki_mean_img = image.mean_img(miyawaki_filename)
plot_epi(miyawaki_mean_img, title='Mean EPI image')
###############################################################################
# A NiftiMasker with the default strategy
masker = NiftiMasker()
masker.fit(miyawaki_filename)

# Plot the generated mask using the mask_img_ attribute
plot_roi(masker.mask_img_,
         miyawaki_mean_img,
         title="Mask from already masked data")

###############################################################################
# Plot the generated mask using the .generate_report method
report = masker.generate_report()
report

###############################################################################
# Computing a mask from raw EPI data
###############################################################################
#
Esempio n. 22
0
def test_cluster_level_parameters_smoke(random_state=0):
    """Test combinations of parameters related to cluster-level inference."""
    import nibabel as nib
    from nilearn.maskers import NiftiMasker

    # create design
    target_var1 = np.arange(0, 10).reshape((-1, 1))  # positive effect
    target_var = np.hstack((  # corresponds to 3 x 3 x 3 x 10 niimg
        target_var1,  # voxel 1 has positive effect
        -target_var1,  # voxel 2 has negative effect
        np.random.random((10, 25)),  # 25 remaining voxels
    ))
    tested_var = np.arange(0, 20, 2)

    mask_img = nib.Nifti1Image(np.ones((3, 3, 3)), np.eye(4))
    masker = NiftiMasker(mask_img)
    masker.fit(mask_img)

    # threshold is defined, indicating cluster-level inference should be done,
    # but masker is not defined.
    with pytest.raises(ValueError):
        permuted_ols(
            tested_var,
            target_var,
            model_intercept=False,
            two_sided_test=False,
            n_perm=100,
            random_state=random_state,
            threshold=0.001,
            masker=None,
        )

    # masker is defined, but threshold is not.
    # no cluster-level inference is performed, but there's a warning.
    with pytest.warns():
        out = permuted_ols(
            tested_var,
            target_var,
            model_intercept=False,
            two_sided_test=False,
            n_perm=100,
            random_state=random_state,
            threshold=None,
            masker=masker,
            output_type="legacy",
        )

    assert isinstance(out, tuple)

    # threshold is defined, but output_type is "legacy".
    # raise a warning, and get a dictionary.
    with pytest.warns():
        out = permuted_ols(
            tested_var,
            target_var,
            model_intercept=False,
            two_sided_test=False,
            n_perm=0,
            random_state=random_state,
            threshold=0.001,
            masker=masker,
            output_type="legacy",
        )

    assert isinstance(out, dict)

    # output_type is "legacy".
    # raise a deprecation warning, but get the standard output.
    with pytest.warns(DeprecationWarning):
        out = permuted_ols(
            tested_var,
            target_var,
            model_intercept=False,
            two_sided_test=False,
            n_perm=100,
            random_state=random_state,
            threshold=None,
            masker=None,
            output_type="legacy",
        )

    assert isinstance(out, tuple)

    # no permutations and output_type is "dict", so check for "t" map
    out = permuted_ols(
        tested_var,
        target_var,
        model_intercept=False,
        two_sided_test=False,
        n_perm=0,
        random_state=random_state,
        threshold=None,
        masker=None,
        output_type="dict",
    )

    assert isinstance(out, dict)
    assert "t" in out.keys()

    # permutations, threshold, and masker are defined,
    # so check for cluster-level maps
    n_perm = 10
    out = permuted_ols(
        tested_var,
        target_var,
        model_intercept=False,
        two_sided_test=True,
        n_perm=n_perm,
        random_state=random_state,
        threshold=0.001,
        masker=masker,
        output_type="dict",
    )

    assert isinstance(out, dict)
    assert "t" in out.keys()
    assert "logp_max_t" in out.keys()
    assert "logp_max_size" in out.keys()
    assert "logp_max_mass" in out.keys()
    assert "h0_max_t" in out.keys()
    assert "h0_max_size" in out.keys()
    assert "h0_max_mass" in out.keys()
    assert out["h0_max_t"].size == n_perm
    assert out["h0_max_size"].size == n_perm
    assert out["h0_max_mass"].size == n_perm
Esempio n. 23
0
def test_compute_brain_mask(strategy, mask_args, expected_mask):
    # Check masker for template masking strategy
    img = _get_random_img((9, 9, 5))
    masker = NiftiMasker(mask_strategy=strategy, mask_args=mask_args)
    masker.fit(img)
    np.testing.assert_array_equal(get_data(masker.mask_img_), expected_mask)