예제 #1
0
    def get_studies_by_mask(self, mask):
        """Extract list of studies with at least one coordinate in mask.

        Parameters
        ----------
        mask : img_like
            Mask across which to search for coordinates.

        Returns
        -------
        found_ids : :obj:`list`
            A list of IDs from the Dataset with at least one focus in the mask.
        """
        from scipy.spatial.distance import cdist

        mask = load_niimg(mask)

        dset_mask = self.masker.mask_img
        if not np.array_equal(dset_mask.affine, mask.affine):
            LGR.warning(
                "Mask affine does not match Dataset affine. Assuming same space."
            )

        dset_ijk = mm2vox(self.coordinates[["x", "y", "z"]].values,
                          mask.affine)
        mask_ijk = np.vstack(np.where(mask.get_fdata())).T
        distances = cdist(mask_ijk, dset_ijk)
        distances = np.any(distances == 0, axis=0)
        found_ids = list(self.coordinates.loc[distances, "id"].unique())
        return found_ids
예제 #2
0
def test_mm2vox():
    """Test mm2vox."""
    test = np.array([[20, 20, 20], [0, 0, 0]])
    true = np.array([[55.0, 73.0, 46.0], [45.0, 63.0, 36.0]])
    img = utils.get_template(space="mni152_2mm", mask=None)
    aff = img.affine
    assert np.array_equal(utils.mm2vox(test, aff), true)
예제 #3
0
def test_meta_fit_performance(meta_res, signal_masks, simulatedata_cbma):
    """Test meta-analytic estimator fit performance."""
    _, (ground_truth_foci, _) = simulatedata_cbma
    mask = meta_res.masker.mask_img
    ground_truth_foci_ijks = [
        tuple(mm2vox(focus, mask.affine)) for focus in ground_truth_foci
    ]
    sig_idx, nonsig_idx = [
        meta_res.masker.transform(img).astype(bool).squeeze()
        for img in signal_masks
    ]

    # all estimators generate p-values
    p_array = meta_res.get_map("p", return_type="array")

    # poor performer(s)
    if (isinstance(meta_res.estimator, ale.ALE) and isinstance(
            meta_res.estimator.kernel_transformer, kernel.KDAKernel)
            and meta_res.estimator.get_params().get("null_method")
            == "approximate"):
        good_sensitivity = True
        good_specificity = False
    elif (isinstance(meta_res.estimator, ale.ALE) and isinstance(
            meta_res.estimator.kernel_transformer, kernel.KDAKernel) and
          "montecarlo" in meta_res.estimator.get_params().get("null_method")):
        good_sensitivity = False
        good_specificity = True
    elif (isinstance(meta_res.estimator, ale.ALE)
          and type(meta_res.estimator.kernel_transformer) == kernel.KDAKernel
          and "montecarlo"
          in meta_res.estimator.get_params().get("null_method")):
        good_sensitivity = False
        good_specificity = True
    elif (isinstance(meta_res.estimator, ale.ALE)
          and type(meta_res.estimator.kernel_transformer) == kernel.KDAKernel
          and meta_res.estimator.get_params().get("null_method")
          == "approximate"):
        good_sensitivity = True
        good_specificity = False
    elif (isinstance(meta_res.estimator, mkda.MKDADensity) and isinstance(
            meta_res.estimator.kernel_transformer, kernel.ALEKernel)
          and meta_res.estimator.get_params().get("null_method") !=
          "reduced_montecarlo"):
        good_sensitivity = False
        good_specificity = True
    else:
        good_sensitivity = True
        good_specificity = True

    _check_p_values(
        p_array,
        meta_res.masker,
        sig_idx,
        nonsig_idx,
        ALPHA,
        ground_truth_foci_ijks,
        n_iters=None,
        good_sensitivity=good_sensitivity,
        good_specificity=good_specificity,
    )
예제 #4
0
def test_mm2vox():
    """
    Test mm2vox
    """
    test = np.array([[20, 20, 20], [0, 0, 0]])
    true = np.array([[35., 73., 46.], [45., 63., 36.]])
    img = utils.get_template(space='mni152_2mm', mask=None)
    aff = img.affine
    assert np.array_equal(utils.mm2vox(test, aff), true)
예제 #5
0
def signal_masks(simulatedata_cbma):
    """Define masks of signal and non-signal for performance evaluation."""
    _, (ground_truth_foci, dataset) = simulatedata_cbma
    ground_truth_foci_ijks = [
        tuple(mm2vox(focus, dataset.masker.mask_img.affine))
        for focus in ground_truth_foci
    ]
    return _create_signal_mask(np.array(ground_truth_foci_ijks),
                               dataset.masker.mask_img)
예제 #6
0
def testdata2():
    mask_img = get_template(space='mni152_2mm', mask='brain')
    df = pd.DataFrame(columns=['id', 'x', 'y', 'z', 'n', 'space'],
                      data=[[1, -28, -20, -16, 20, 'mni'],
                            [2, -28, -20, -16, 5, 'mni']])
    xyz = df[['x', 'y', 'z']].values
    ijk = pd.DataFrame(mm2vox(xyz, mask_img.affine), columns=['i', 'j', 'k'])
    df = pd.concat([df, ijk], axis=1)

    dset = DummyDataset(df, mask_img)
    return dset
예제 #7
0
def test_kernel_peaks(testdata_cbma, tmp_path_factory, kern, res, param,
                      return_type, kwargs):
    """Peak/COMs of kernel maps should match the foci fed in (assuming focus isn't masked out).

    Notes
    -----
    Remember that dataframe --> dataset won't work.
    Only testing dataset --> dataset with ALEKernel because it takes a while.
    Test on multiple template resolutions.
    """
    tmpdir = tmp_path_factory.mktemp("test_kernel_peaks")
    testdata_cbma.update_path(tmpdir)

    id_ = "pain_03.nidm-1"

    # Ignoring resolution until we support 0.8.1
    # template = load_mni152_brain_mask(resolution=res)
    template = load_mni152_brain_mask()
    masker = get_masker(template)

    xyz = testdata_cbma.coordinates.loc[testdata_cbma.coordinates["id"] == id_,
                                        ["x", "y", "z"]]
    ijk = mm2vox(xyz, masker.mask_img.affine)
    ijk = np.squeeze(ijk.astype(int))

    if param == "dataframe":
        input_ = testdata_cbma.coordinates.copy()
    elif param == "dataset":
        input_ = testdata_cbma.copy()

    kern_instance = kern(**kwargs)
    output = kern_instance.transform(input_, masker, return_type=return_type)

    if return_type == "image":
        kern_data = output[0].get_fdata()
    elif return_type == "array":
        kern_data = np.squeeze(
            masker.inverse_transform(output[:1, :]).get_fdata())
    else:
        f = output.images.loc[output.images["id"] == id_,
                              kern_instance.image_type].values[0]
        kern_data = nib.load(f).get_fdata()

    if isinstance(kern_instance, kernel.ALEKernel):
        loc_idx = np.array(np.where(kern_data == np.max(kern_data))).T
    elif isinstance(kern_instance, (kernel.MKDAKernel, kernel.KDAKernel)):
        loc_idx = np.array(center_of_mass(kern_data)).astype(int).T
    else:
        raise Exception(f"A {type(kern_instance)}? Why?")

    loc_ijk = np.squeeze(loc_idx)

    assert np.array_equal(ijk, loc_ijk)
예제 #8
0
파일: conftest.py 프로젝트: alexprz/NiMARE
def cbma_testdata3():
    """
    Reduced dataset for SCALE test.
    """
    mask_img = get_template(space='mni152_2mm', mask='brain')
    mask_img = nib.Nifti1Image(np.ones((10, 10, 10), int), mask_img.affine)
    df = pd.DataFrame(columns=['id', 'x', 'y', 'z', 'n', 'space'],
                      data=[[1, -28, -20, -16, 100, 'mni'],
                            [2, -28, -20, -16, 100, 'mni'],
                            [3, -28, -20, -16, 100, 'mni']])
    xyz = df[['x', 'y', 'z']].values
    ijk = pd.DataFrame(mm2vox(xyz, mask_img.affine), columns=['i', 'j', 'k'])
    df = pd.concat([df, ijk], axis=1)

    dset = DummyDataset(df, mask_img)
    pytest.cbma_testdata3 = dset
예제 #9
0
    def _transform(self, expid, coordinates_df, labeled_cluster_map, affine):
        coords = coordinates_df.loc[coordinates_df["id"] == expid]
        ijk = mm2vox(coords[["x", "y", "z"]], affine)

        clust_ids = sorted(list(np.unique(labeled_cluster_map)[1:]))
        focus_counts = []

        for i_cluster, c_val in enumerate(clust_ids):
            cluster_mask = labeled_cluster_map == c_val
            cluster_idx = np.vstack(np.where(cluster_mask))
            distances = cdist(cluster_idx.T, ijk)
            distances = distances < 1
            distances = np.any(distances, axis=0)
            n_included_voxels = np.sum(distances)
            focus_counts.append(n_included_voxels)

        return expid, focus_counts
예제 #10
0
def test_ALEKernel_sample_size(testdata_cbma):
    """Peaks of ALE kernel maps should match the foci fed in (assuming focus isn't masked out).

    Test with explicit sample size.
    """
    coordinates = testdata_cbma.coordinates.copy()

    id_ = "pain_03.nidm-1"
    kern = kernel.ALEKernel(sample_size=20)
    ma_maps = kern.transform(coordinates, masker=testdata_cbma.masker, return_type="image")

    xyz = coordinates.loc[coordinates["id"] == id_, ["x", "y", "z"]]
    ijk = mm2vox(xyz, testdata_cbma.masker.mask_img.affine)
    ijk = np.squeeze(ijk.astype(int))

    kern_data = ma_maps[0].get_fdata()
    max_idx = np.array(np.where(kern_data == np.max(kern_data))).T
    max_ijk = np.squeeze(max_idx)
    assert np.array_equal(ijk, max_ijk)
예제 #11
0
파일: conftest.py 프로젝트: alexprz/NiMARE
def cbma_testdata1():
    mask_img = get_template(space='mni152_2mm', mask='brain')
    df = pd.DataFrame(columns=['id', 'x', 'y', 'z', 'n', 'space'],
                      data=[[1, -28, -20, -16, 100, 'mni'],
                            [2, -28, -20, -16, 100, 'mni'],
                            [3, -28, -20, -16, 100, 'mni'],
                            [4, -28, -20, -16, 100, 'mni'],
                            [5, -28, -20, -16, 100, 'mni'],
                            [6, -28, -20, -16, 100, 'mni'],
                            [7, -28, -20, -16, 100, 'mni'],
                            [8, -28, -20, -16, 100, 'mni'],
                            [9, -28, -20, -16, 100, 'mni'],
                            [10, -28, -20, -16, 100, 'mni'],
                            [11, -28, -20, -16, 100, 'mni']])
    xyz = df[['x', 'y', 'z']].values
    ijk = pd.DataFrame(mm2vox(xyz, mask_img.affine), columns=['i', 'j', 'k'])
    df = pd.concat([df, ijk], axis=1)

    dset = DummyDataset(df, mask_img)
    pytest.cbma_testdata1 = dset
예제 #12
0
    def transform(self, dataset, masker=None, return_type="image"):
        """Generate modeled activation images for each Contrast in dataset.

        Parameters
        ----------
        dataset : :obj:`~nimare.dataset.Dataset` or :obj:`pandas.DataFrame`
            Dataset for which to make images. Can be a DataFrame if necessary.
        masker : img_like or None, optional
            Mask to apply to MA maps. Required if ``dataset`` is a DataFrame.
            If None (and ``dataset`` is a Dataset), the Dataset's masker attribute will be used.
            Default is None.
        return_type : {'sparse', 'array', 'image', 'dataset'}, optional
            Whether to return a numpy array ('array'), a list of niimgs ('image'),
            or a Dataset with MA images saved as files ('dataset').
            Default is 'image'.

        Returns
        -------
        imgs : (C x V) :class:`numpy.ndarray` or :obj:`list` of :class:`nibabel.Nifti1Image` \
               or :class:`~nimare.dataset.Dataset`
            If return_type is 'sparse', a 4D sparse array (E x S), where E is
            the number of unique experiments, and the remaining 3 dimensions are
            equal to `shape` of the images.
            If return_type is 'array', a 2D numpy array (C x V), where C is
            contrast and V is voxel.
            If return_type is 'image', a list of modeled activation images
            (one for each of the Contrasts in the input dataset).
            If return_type is 'dataset', a new Dataset object with modeled
            activation images saved to files and referenced in the
            Dataset.images attribute.

        Attributes
        ----------
        filename_pattern : str
            Filename pattern for MA maps that will be saved by the transformer.
        image_type : str
            Name of the corresponding column in the Dataset.images DataFrame.
        """
        if return_type not in ("sparse", "array", "image", "dataset"):
            raise ValueError(
                'Argument "return_type" must be "image", "array", or "dataset".'
            )

        if isinstance(dataset, pd.DataFrame):
            assert (
                masker is not None
            ), "Argument 'masker' must be provided if dataset is a DataFrame."
            mask = masker.mask_img
            coordinates = dataset
            assert (
                return_type != "dataset"
            ), "Input dataset must be a Dataset if return_type='dataset'."

            # Calculate IJK. Must assume that the masker is in same space,
            # but has different affine, from original IJK.
            coordinates[["i", "j", "k"]] = mm2vox(dataset[["x", "y", "z"]],
                                                  mask.affine)
        else:
            masker = dataset.masker if not masker else masker
            mask = masker.mask_img
            coordinates = dataset.coordinates.copy()

            # Determine MA map filenames. Must happen after parameters are set.
            self._infer_names(affine=md5(mask.affine).hexdigest())

            # Check for existing MA maps
            # Use coordinates to get IDs instead of Dataset.ids bc of possible
            # mismatch between full Dataset and contrasts with coordinates.
            if self.image_type in dataset.images.columns:
                files = dataset.get_images(ids=coordinates["id"].unique(),
                                           imtype=self.image_type)
                if all(f is not None for f in files):
                    LGR.debug("Files already exist. Using them.")
                    if return_type == "array":
                        masked_data = _safe_transform(files, masker)
                        return masked_data
                    elif return_type == "image":
                        return [nib.load(f) for f in files]
                    elif return_type == "dataset":
                        return dataset.copy()

            # Calculate IJK
            if not np.array_equal(mask.affine, dataset.masker.mask_img.affine):
                LGR.warning(
                    "Mask affine does not match Dataset affine. Assuming same space."
                )

            coordinates[["i", "j", "k"]] = mm2vox(coordinates[["x", "y", "z"]],
                                                  mask.affine)

            # Add any metadata the Transformer might need to the coordinates DataFrame
            # This approach is probably inferior to one which uses a _required_inputs attribute
            # (like the MetaEstimators), but it should work just fine as long as individual
            # requirements are written in here.
            if (hasattr(self, "sample_size") and (self.sample_size is None)
                    and ("sample_size" not in coordinates.columns)):
                coordinates = _add_metadata_to_dataframe(
                    dataset,
                    coordinates,
                    metadata_field="sample_sizes",
                    target_column="sample_size",
                    filter_func=np.mean,
                )

        # Generate the MA maps if they weren't already available as images
        if return_type == "array":
            mask_data = mask.get_fdata().astype(bool)
        elif return_type == "image":
            dtype = type(self.value) if hasattr(self, "value") else float
            mask_data = mask.get_fdata().astype(dtype)
        elif return_type == "dataset":
            if dataset.basepath is None:
                raise ValueError(
                    "Dataset output path is not set. Set the path with Dataset.update_path()."
                )
            elif not os.path.isdir(dataset.basepath):
                raise ValueError(
                    "Output directory does not exist. Set the path to an existing folder with "
                    "Dataset.update_path().")
            dataset = dataset.copy()

        transformed_maps = self._transform(mask, coordinates)

        if return_type == "sparse":
            return transformed_maps[0]

        imgs = []
        # Loop over exp ids since sparse._coo.core.COO is not iterable
        for i_exp, id_ in enumerate(transformed_maps[1]):
            if isinstance(transformed_maps[0][i_exp], sparse._coo.core.COO):
                kernel_data = transformed_maps[0][i_exp].todense()
            else:
                kernel_data = transformed_maps[0][i_exp]

            if return_type == "array":
                img = kernel_data[mask_data]
                imgs.append(img)
            elif return_type == "image":
                kernel_data *= mask_data
                img = nib.Nifti1Image(kernel_data, mask.affine)
                imgs.append(img)
            elif return_type == "dataset":
                img = nib.Nifti1Image(kernel_data, mask.affine)
                out_file = os.path.join(dataset.basepath,
                                        self.filename_pattern.format(id=id_))
                img.to_filename(out_file)
                dataset.images.loc[dataset.images["id"] == id_,
                                   self.image_type] = out_file

        del kernel_data, transformed_maps

        if return_type == "array":
            return np.vstack(imgs)
        elif return_type == "image":
            return imgs
        elif return_type == "dataset":
            # Replace NaNs with Nones
            dataset.images[self.image_type] = dataset.images[
                self.image_type].where(
                    dataset.images[self.image_type].notnull(), None)
            # Infer relative path
            dataset.images = dataset.images
            return dataset
예제 #13
0
def _create_foci(foci, foci_percentage, fwhm, n_studies, n_noise_foci, rng,
                 space):
    """Generate study specific foci.

    .. versionadded:: 0.0.4

    Parameters
    ----------
    foci : :obj:`int` or :obj:`list`
        The number of foci to be generated per study or the
        x,y,z coordinates of the ground truth foci.
    foci_percentage : :obj:`float`
        Percentage of studies where the foci appear.
    fwhm : :obj:`float`
        Full width at half maximum (fwhm) to define the probability
        spread of the foci.
    n_studies : :obj:`int`
        Number of n_studies to generate.
    n_noise_foci : :obj:`int`
        Number of foci considered to be noise in each study.
    rng : :class:`numpy.random.RandomState`
        Random state to reproducibly initialize random numbers.
    space : :obj:`str`
        The template space the coordinates are reported in.

    Returns
    -------
    ground_truth_foci : :obj:`list`
        List of 3-item tuples containing x, y, z coordinates
        of the ground truth foci or an empty list if
        there are no ground_truth_foci.
    foci_dict : :obj:`dict`
        Dictionary with keys representing the study, and
        whose values represent the study specific foci.
    """
    # convert foci_percentage to float between 0 and 1
    if isinstance(foci_percentage, str) and foci_percentage[-1] == "%":
        foci_percentage = float(foci_percentage[:-1]) / 100

    if space == "MNI":
        template_img = get_template(space="mni152_2mm", mask="brain")

    # use a template to find all "valid" coordinates
    template_data = template_img.get_fdata()
    possible_ijks = np.argwhere(template_data)

    # number of "convergent" foci each study should report
    if isinstance(foci, int):
        foci_idxs = np.unique(
            rng.choice(range(possible_ijks.shape[0]), foci, replace=True))
        # if there are no foci_idxs, give a dummy coordinate (0, 0, 0)
        ground_truth_foci_ijks = possible_ijks[
            foci_idxs] if foci_idxs.size else np.array([[]])
    elif isinstance(foci, list):
        ground_truth_foci_ijks = np.array(
            [mm2vox(coord, template_img.affine) for coord in foci])

    # create a probability map for each peak
    kernel = get_ale_kernel(template_img, fwhm)[1]
    foci_prob_maps = {
        tuple(peak): compute_ale_ma(template_data.shape, np.atleast_2d(peak),
                                    kernel)
        for peak in ground_truth_foci_ijks if peak.size
    }

    # get study specific instances of each foci
    signal_studies = int(round(foci_percentage * n_studies))
    signal_ijks = {
        peak: np.argwhere(prob_map)[rng.choice(
            np.argwhere(prob_map).shape[0],
            size=signal_studies,
            replace=True,
            p=prob_map[np.nonzero(prob_map)] /
            sum(prob_map[np.nonzero(prob_map)]),
        )]
        for peak, prob_map in foci_prob_maps.items()
    }

    # reshape foci coordinates to be study specific
    paired_signal_ijks = (np.transpose(np.array(list(signal_ijks.values())),
                                       axes=(1, 0, 2)) if signal_ijks else
                          (None, ))

    foci_dict = {}
    for study_signal_ijks, study in zip_longest(paired_signal_ijks,
                                                range(n_studies)):
        if study_signal_ijks is None:
            study_signal_ijks = np.array([[]])
            n_noise_foci = max(1, n_noise_foci)

        if n_noise_foci > 0:
            noise_ijks = possible_ijks[rng.choice(possible_ijks.shape[0],
                                                  n_noise_foci,
                                                  replace=True)]

            # add the noise foci ijks to the existing signal ijks
            foci_ijks = (np.unique(np.vstack([study_signal_ijks, noise_ijks]),
                                   axis=0)
                         if np.any(study_signal_ijks) else noise_ijks)
        else:
            foci_ijks = study_signal_ijks

        # transform ijk voxel coordinates to xyz mm coordinates
        foci_xyzs = [vox2mm(ijk, template_img.affine) for ijk in foci_ijks]
        foci_dict[study] = foci_xyzs

    ground_truth_foci_xyz = [
        tuple(vox2mm(ijk, template_img.affine))
        for ijk in ground_truth_foci_ijks if np.any(ijk)
    ]
    return ground_truth_foci_xyz, foci_dict
예제 #14
0
    def _preprocess_input(self, dataset):
        """Preprocess inputs to the Estimator from the Dataset as needed."""
        masker = self.masker or dataset.masker

        mask_img = masker.mask_img or masker.labels_img
        if isinstance(mask_img, str):
            mask_img = nb.load(mask_img)

        # Ensure that protected values are not included among _required_inputs
        assert "aggressive_mask" not in self._required_inputs.keys(), "This is a protected name."

        if "aggressive_mask" in self.inputs_.keys():
            LGR.warning("Removing existing 'aggressive_mask' from Estimator.")
            self.inputs_.pop("aggressive_mask")

        # A dictionary to collect masked image data, to be further reduced by the aggressive mask.
        temp_image_inputs = {}

        for name, (type_, _) in self._required_inputs.items():
            if type_ == "image":
                # If no resampling is requested, check if resampling is required
                if not self.resample:
                    check_imgs = {img: nb.load(img) for img in self.inputs_[name]}
                    _check_same_fov(**check_imgs, reference_masker=mask_img, raise_error=True)
                    imgs = list(check_imgs.values())
                else:
                    # resampling will only occur if shape/affines are different
                    # making this harmless if all img shapes/affines are the same as the reference
                    imgs = [
                        resample_to_img(nb.load(img), mask_img, **self._resample_kwargs)
                        for img in self.inputs_[name]
                    ]

                # input to NiFtiLabelsMasker must be 4d
                img4d = concat_imgs(imgs, ensure_ndim=4)

                # Mask required input images using either the dataset's mask or the estimator's.
                temp_arr = masker.transform(img4d)

                # An intermediate step to mask out bad voxels.
                # Can be dropped once PyMARE is able to handle masked arrays or missing data.
                nonzero_voxels_bool = np.all(temp_arr != 0, axis=0)
                nonnan_voxels_bool = np.all(~np.isnan(temp_arr), axis=0)
                good_voxels_bool = np.logical_and(nonzero_voxels_bool, nonnan_voxels_bool)

                data = masker.transform(img4d)

                temp_image_inputs[name] = data
                if "aggressive_mask" not in self.inputs_.keys():
                    self.inputs_["aggressive_mask"] = good_voxels_bool
                else:
                    # Remove any voxels that are bad in any image-based inputs
                    self.inputs_["aggressive_mask"] = np.logical_or(
                        self.inputs_["aggressive_mask"],
                        good_voxels_bool,
                    )

            elif type_ == "coordinates":
                # Try to load existing MA maps
                if hasattr(self, "kernel_transformer"):
                    self.kernel_transformer._infer_names(affine=md5(mask_img.affine).hexdigest())
                    if self.kernel_transformer.image_type in dataset.images.columns:
                        files = dataset.get_images(
                            ids=self.inputs_["id"],
                            imtype=self.kernel_transformer.image_type,
                        )
                        if all(f is not None for f in files):
                            self.inputs_["ma_maps"] = files

                # Calculate IJK matrix indices for target mask
                # Mask space is assumed to be the same as the Dataset's space
                # These indices are used directly by any KernelTransformer
                xyz = self.inputs_["coordinates"][["x", "y", "z"]].values
                ijk = mm2vox(xyz, mask_img.affine)
                self.inputs_["coordinates"][["i", "j", "k"]] = ijk

        # Further reduce image-based inputs to remove "bad" voxels
        # (voxels with zeros or NaNs in any studies)
        if "aggressive_mask" in self.inputs_.keys():
            n_bad_voxels = (
                self.inputs_["aggressive_mask"].size - self.inputs_["aggressive_mask"].sum()
            )
            if n_bad_voxels:
                LGR.warning(
                    f"Masking out {n_bad_voxels} additional voxels. "
                    "The updated masker is available in the Estimator.masker attribute."
                )

            for name, raw_masked_data in temp_image_inputs.items():
                self.inputs_[name] = raw_masked_data[:, self.inputs_["aggressive_mask"]]
예제 #15
0
파일: base.py 프로젝트: neurostuff/NiMARE
    def _preprocess_input(self, dataset):
        """Mask required input images using either the Dataset's mask or the Estimator's.

        Also, insert required metadata into coordinates DataFrame.

        Parameters
        ----------
        dataset : :obj:`~nimare.dataset.Dataset`
            In this method, the Dataset is used to (1) select the appropriate mask image,
            (2) identify any pre-generated MA maps stored in its images attribute,
            and (3) extract sample size metadata and place it into the coordinates input.

        Attributes
        ----------
        inputs_ : :obj:`dict`
            This attribute (created by ``_collect_inputs()``) is updated in this method.
            Specifically, (1) an "ma_maps" key may be added if pre-generated MA maps are available,
            (2) IJK coordinates will be added based on the mask image's affine,
            and (3) sample sizes may be added to the "coordinates" key, as needed.
        """
        masker = self.masker or dataset.masker

        mask_img = masker.mask_img or masker.labels_img
        if isinstance(mask_img, str):
            mask_img = nib.load(mask_img)

        for name, (type_, _) in self._required_inputs.items():
            if type_ == "coordinates":
                # Try to load existing MA maps
                if hasattr(self, "kernel_transformer"):
                    self.kernel_transformer._infer_names(
                        affine=md5(mask_img.affine).hexdigest())
                    if self.kernel_transformer.image_type in dataset.images.columns:
                        files = dataset.get_images(
                            ids=self.inputs_["id"],
                            imtype=self.kernel_transformer.image_type,
                        )
                        if all(f is not None for f in files):
                            self.inputs_["ma_maps"] = files

                # Calculate IJK matrix indices for target mask
                # Mask space is assumed to be the same as the Dataset's space
                # These indices are used directly by any KernelTransformer
                xyz = self.inputs_["coordinates"][["x", "y", "z"]].values
                ijk = mm2vox(xyz, mask_img.affine)
                self.inputs_["coordinates"][["i", "j", "k"]] = ijk

        # All extra (non-ijk) parameters for a kernel should be overrideable as
        # parameters to __init__, so we can access them with get_params()
        kt_args = list(self.kernel_transformer.get_params().keys())

        # Integrate "sample_size" from metadata into DataFrame so that
        # kernel_transformer can access it.
        if "sample_size" in kt_args:
            self.inputs_["coordinates"] = _add_metadata_to_dataframe(
                dataset,
                self.inputs_["coordinates"],
                metadata_field="sample_sizes",
                target_column="sample_size",
                filter_func=np.mean,
            )
예제 #16
0
def test_corr_transform_performance(meta_cres, corr, signal_masks,
                                    simulatedata_cbma):
    """Test corrector transform performance."""
    _, (ground_truth_foci, _) = simulatedata_cbma
    mask = meta_cres.masker.mask_img
    ground_truth_foci_ijks = [
        tuple(mm2vox(focus, mask.affine)) for focus in ground_truth_foci
    ]
    sig_idx, nonsig_idx = [
        meta_cres.masker.transform(img).astype(bool).squeeze()
        for img in signal_masks
    ]

    p_array = meta_cres.maps.get("p")
    if p_array is None or corr.method == "montecarlo":
        p_array = 10**-meta_cres.maps.get(
            "logp_level-voxel_corr-FWE_method-montecarlo")

    n_iters = corr.parameters.get("n_iters")

    # ALE with MKDA kernel with montecarlo correction
    # combination gives poor performance
    if (isinstance(meta_cres.estimator, ale.ALE) and isinstance(
            meta_cres.estimator.kernel_transformer, kernel.MKDAKernel)
            and meta_cres.estimator.get_params().get("null_method")
            == "approximate" and corr.method != "montecarlo"):
        good_sensitivity = True
        good_specificity = False
    elif (isinstance(meta_cres.estimator, ale.ALE) and isinstance(
            meta_cres.estimator.kernel_transformer, kernel.MKDAKernel) and
          "montecarlo" in meta_cres.estimator.get_params().get("null_method")):
        good_sensitivity = False
        good_specificity = True
    elif (isinstance(meta_cres.estimator, ale.ALE) and isinstance(
            meta_cres.estimator.kernel_transformer, kernel.MKDAKernel) and
          meta_cres.estimator.get_params().get("null_method") == "approximate"
          and corr.method == "montecarlo"):
        good_sensitivity = False
        good_specificity = True
    elif (
            isinstance(meta_cres.estimator, ale.ALE) and type(
                meta_cres.estimator.kernel_transformer) == kernel.KDAKernel and
        ("montecarlo" in meta_cres.estimator.get_params().get("null_method") or
         (meta_cres.estimator.get_params().get("null_method") == "approximate"
          and corr.method == "montecarlo"))):
        good_sensitivity = False
        good_specificity = True
    elif (isinstance(meta_cres.estimator, ale.ALE)
          and type(meta_cres.estimator.kernel_transformer) == kernel.KDAKernel
          and meta_cres.estimator.get_params().get("null_method")
          == "approximate"):
        good_sensitivity = True
        good_specificity = False
    elif (isinstance(meta_cres.estimator, mkda.MKDADensity) and isinstance(
            meta_cres.estimator.kernel_transformer, kernel.ALEKernel)
          and meta_cres.estimator.get_params().get("null_method") !=
          "reduced_montecarlo" and corr.method != "montecarlo"):
        good_sensitivity = False
        good_specificity = True
    else:
        good_sensitivity = True
        good_specificity = True

    _check_p_values(
        p_array,
        meta_cres.masker,
        sig_idx,
        nonsig_idx,
        ALPHA,
        ground_truth_foci_ijks,
        n_iters=n_iters,
        good_sensitivity=good_sensitivity,
        good_specificity=good_specificity,
    )