Skip to content

Commit

Permalink
Add support for the concordant mode test in Fisher's and Stouffer's…
Browse files Browse the repository at this point in the history
… estimators
  • Loading branch information
JulioAPeraza committed May 17, 2024
1 parent ac9792d commit 15223b9
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 6 deletions.
8 changes: 7 additions & 1 deletion nimare/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,13 @@ def transform(self, result):

# Get clusters table and label maps
stat_threshold = self.voxel_thresh or 0
two_sided = (target_img.get_fdata() < 0).any()

if hasattr(result.estimator, "two_sided"):
# Only present in Fisher's and Stouffer's estimators
two_sided = getattr(result.estimator, "two_sided")
else:
two_sided = (target_img.get_fdata() < 0).any()

clusters_table, label_maps = get_clusters_table(
target_img,
stat_threshold,
Expand Down
36 changes: 31 additions & 5 deletions nimare/meta/ibma.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ class Fishers(IBMAEstimator):
This method is described in :footcite:t:`fisher1946statistical`.
.. versionchanged:: 0.2.3
* New parameter: ``two_sided``, to control the type of test to perform.
.. versionchanged:: 0.2.1
* New parameter: ``aggressive_mask``, to control whether to use an aggressive mask.
Expand All @@ -184,6 +188,11 @@ class Fishers(IBMAEstimator):
If False, all voxels are included by running a separate analysis on bags
of voxels that belong that have a valid value across the same studies.
Default is True.
two_sided : :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 is True.
Notes
-----
Expand Down Expand Up @@ -220,6 +229,11 @@ class Fishers(IBMAEstimator):

_required_inputs = {"z_maps": ("image", "z")}

def __init__(self, two_sided=True, **kwargs):
super().__init__(**kwargs)
self.two_sided = two_sided
self._mode = "concordant" if self.two_sided else "directed"

def _generate_description(self):
description = (
f"An image-based meta-analysis was performed with NiMARE {__version__} "
Expand All @@ -242,7 +256,7 @@ def _fit(self, dataset):

if self.aggressive_mask:
pymare_dset = pymare.Dataset(y=self.inputs_["z_maps"])
est = pymare.estimators.FisherCombinationTest()
est = pymare.estimators.FisherCombinationTest(mode=self._mode)
est.fit_dataset(pymare_dset)
est_summary = est.summary()

Expand All @@ -261,7 +275,7 @@ def _fit(self, dataset):
dof_map = np.zeros(n_total_voxels, dtype=np.int32)
for bag in self.inputs_["data_bags"]["z_maps"]:
pymare_dset = pymare.Dataset(y=bag["values"])
est = pymare.estimators.FisherCombinationTest()
est = pymare.estimators.FisherCombinationTest(mode=self._mode)
est.fit_dataset(pymare_dset)
est_summary = est.summary()
z_map[bag["voxel_mask"]] = est_summary.z.squeeze()
Expand All @@ -281,6 +295,10 @@ class Stouffers(IBMAEstimator):
This method is described in :footcite:t:`stouffer1949american`.
.. versionchanged:: 0.2.3
* New parameter: ``two_sided``, to control the type of test to perform.
.. versionchanged:: 0.2.1
* New parameter: ``aggressive_mask``, to control whether to use an aggressive mask.
Expand All @@ -297,6 +315,11 @@ class Stouffers(IBMAEstimator):
Whether to use sample sizes for weights (i.e., "weighted Stouffer's") or not,
as described in :footcite:t:`zaykin2011optimally`.
Default is False.
two_sided : :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 is True.
Notes
-----
Expand Down Expand Up @@ -333,12 +356,15 @@ class Stouffers(IBMAEstimator):

_required_inputs = {"z_maps": ("image", "z")}

def __init__(self, use_sample_size=False, **kwargs):
def __init__(self, use_sample_size=False, two_sided=True, **kwargs):
super().__init__(**kwargs)
self.use_sample_size = use_sample_size
if self.use_sample_size:
self._required_inputs["sample_sizes"] = ("metadata", "sample_sizes")

self.two_sided = two_sided
self._mode = "concordant" if self.two_sided else "directed"

def _generate_description(self):
description = (
f"An image-based meta-analysis was performed with NiMARE {__version__} "
Expand Down Expand Up @@ -369,7 +395,7 @@ def _fit(self, dataset):
)

if self.aggressive_mask:
est = pymare.estimators.StoufferCombinationTest()
est = pymare.estimators.StoufferCombinationTest(mode=self._mode)

if self.use_sample_size:
sample_sizes = np.array([np.mean(n) for n in self.inputs_["sample_sizes"]])
Expand All @@ -395,7 +421,7 @@ def _fit(self, dataset):
p_map = np.zeros(n_total_voxels, dtype=float)
dof_map = np.zeros(n_total_voxels, dtype=np.int32)
for bag in self.inputs_["data_bags"]["z_maps"]:
est = pymare.estimators.StoufferCombinationTest()
est = pymare.estimators.StoufferCombinationTest(mode=self._mode)

if self.use_sample_size:
study_mask = bag["study_mask"]
Expand Down
13 changes: 13 additions & 0 deletions nimare/resources/references.bib
Original file line number Diff line number Diff line change
Expand Up @@ -529,3 +529,16 @@ @article{geoffroy2001poisson
year={2001},
publisher={Taylor \& Francis}
}

@article{winkler2016non,
title={Non-parametric combination and related permutation tests for neuroimaging},
author={Winkler, Anderson M and Webster, Matthew A and Brooks, Jonathan C and Tracey, Irene and Smith, Stephen M and Nichols, Thomas E},
journal={Human brain mapping},
volume={37},
number={4},
pages={1486--1511},
year={2016},
publisher={Wiley Online Library},
url={https://doi.org/10.1002/hbm.23115},
doi={10.1002/hbm.23115}
}

0 comments on commit 15223b9

Please sign in to comment.