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
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)
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, )
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)
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)
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
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)
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
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
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)
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
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
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
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"]]
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, )
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, )