Skip to content

Commit 1d4a94f

Browse files
committed
Merge branch 'eg-refactor-regression' into main-master
* eg-refactor-regression: BF: fix parallel example to run permutation test update parallel fiac example for IPython.parallel BF+DOC: fixing permutation test example
2 parents 3467bbc + ac0f0b2 commit 1d4a94f

File tree

2 files changed

+129
-84
lines changed

2 files changed

+129
-84
lines changed

examples/fiac/fiac_example.py

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,19 @@
22
# vi: set ft=python sts=4 ts=4 sw=4 et:
33
"""Example analyzing the FIAC dataset with NIPY.
44
5+
* Single run models with per-voxel AR(1).
6+
* Cross-run, within-subject models with optimal effect estimates.
7+
* Cross-subject models using fixed / random effects variance ratios.
8+
* Permutation testing for inference on cross-subject result.
9+
10+
See ``parallel_run.py`` for a rig to run these analysis in parallel using the
11+
IPython parallel machinery.
12+
513
This script needs the pre-processed FIAC data. See ``README.txt`` and
614
``fiac_util.py`` for details.
715
816
See ``examples/labs/need_data/first_level_fiac.py`` for an alternative approach
9-
to this analysis.
17+
to some of these analyses.
1018
"""
1119
#-----------------------------------------------------------------------------
1220
# Imports
@@ -281,17 +289,17 @@ def fixed_effects(subj, design):
281289
fixdir = pjoin(rootdir, "fixed")
282290
# Fetch results images from run estimations
283291
results = futil.results_table(path_dict)
284-
# Get our hands on the relevant coordmap to
285-
# save our results
292+
# Get our hands on the relevant coordmap to save our results
286293
coordmap = futil.load_image_fiac("fiac_%02d" % subj,
287294
"wanatomical.nii").coordmap
288295
# Compute the "fixed" effects for each type of contrast
289296
for con in results:
290297
fixed_effect = 0
291298
fixed_var = 0
292299
for effect, sd in results[con]:
293-
effect = load_image(effect); sd = load_image(sd)
294-
var = np.array(sd)**2
300+
effect = load_image(effect).get_data()
301+
sd = load_image(sd).get_data()
302+
var = sd ** 2
295303

296304
# The optimal, in terms of minimum variance, combination of the
297305
# effects has weights 1 / var
@@ -332,9 +340,19 @@ def group_analysis(design, contrast):
332340

333341
# Which subjects have this (contrast, design) pair?
334342
subj_con_dirs = futil.subj_des_con_dirs(design, contrast)
335-
336-
sd = array([array(load_image(pjoin(s, "sd.nii"))) for s in subj_con_dirs])
337-
Y = array([array(load_image(pjoin(s, "effect.nii"))) for s in subj_con_dirs])
343+
if len(subj_con_dirs) == 0:
344+
raise ValueError('No subjects for %s, %s' % (design, contrast))
345+
346+
# Assemble effects and sds into 4D arrays
347+
sds = []
348+
Ys = []
349+
for s in subj_con_dirs:
350+
sd_img = load_image(pjoin(s, "sd.nii"))
351+
effect_img = load_image(pjoin(s, "effect.nii"))
352+
sds.append(sd_img.get_data())
353+
Ys.append(effect_img.get_data())
354+
sd = array(sds)
355+
Y = array(Ys)
338356

339357
# This function estimates the ratio of the fixed effects variance
340358
# (sum(1/sd**2, 0)) to the estimated random effects variance
@@ -378,7 +396,9 @@ def group_analysis_signs(design, contrast, mask, signs=None):
378396
----------
379397
design: one of 'block', 'event'
380398
contrast: str
381-
mask: array-like
399+
name of contrast to estimate
400+
mask : ``Image`` instance or array-like
401+
image containing mask, or array-like
382402
signs: ndarray, optional
383403
Defaults to np.ones. Should have shape (*,nsubj)
384404
where nsubj is the number of effects combined in the group analysis.
@@ -390,15 +410,25 @@ def group_analysis_signs(design, contrast, mask, signs=None):
390410
maxT: np.ndarray, maxima of T statistic within mask, one for each
391411
vector of signs
392412
"""
393-
maska = np.asarray(mask).astype(np.bool)
413+
if api.is_image(mask):
414+
maska = mask.get_data()
415+
else:
416+
maska = np.asarray(mask)
417+
maska = maska.astype(np.bool)
394418

395419
# Which subjects have this (contrast, design) pair?
396420
subj_con_dirs = futil.subj_des_con_dirs(design, contrast)
397421

398-
sd = np.array([np.array(load_image(pjoin(s, "sd.nii")))[:,maska]
399-
for s in subj_con_dirs])
400-
Y = np.array([np.array(load_image(pjoin(s, "effect.nii")))[:,maska]
401-
for s in subj_con_dirs])
422+
# Assemble effects and sds into 4D arrays
423+
sds = []
424+
Ys = []
425+
for s in subj_con_dirs:
426+
sd_img = load_image(pjoin(s, "sd.nii"))
427+
effect_img = load_image(pjoin(s, "effect.nii"))
428+
sds.append(sd_img.get_data()[maska])
429+
Ys.append(effect_img.get_data()[maska])
430+
sd = np.array(sds)
431+
Y = np.array(Ys)
402432

403433
if signs is None:
404434
signs = np.ones((1, Y.shape[0]))
@@ -428,22 +458,26 @@ def permutation_test(design, contrast, mask=GROUP_MASK, nsample=1000):
428458
429459
Parameters
430460
----------
431-
design: one of ['block', 'event']
432-
contrast: str
433-
nsample: int
461+
design: str
462+
one of ['block', 'event']
463+
contrast : str
464+
name of contrast to estimate
465+
mask : ``Image`` instance or array-like, optional
466+
image containing mask, or array-like
467+
nsample: int, optional
468+
number of permutations
434469
435470
Returns
436471
-------
437472
min_vals: np.ndarray
438473
max_vals: np.ndarray
439474
"""
440-
maska = np.asarray(mask).astype(np.bool)
441475
subj_con_dirs = futil.subj_des_con_dirs(design, contrast)
442-
Y = np.array([np.array(load_image(pjoin(s, "effect.nii")))[:,maska]
443-
for s in subj_con_dirs])
444-
nsubj = Y.shape[0]
476+
nsubj = len(subj_con_dirs)
477+
if nsubj == 0:
478+
raise ValueError('No subjects have %s, %s' % (design, contrast))
445479
signs = 2*np.greater(np.random.sample(size=(nsample, nsubj)), 0.5) - 1
446-
min_vals, max_vals = group_analysis_signs(design, contrast, maska, signs)
480+
min_vals, max_vals = group_analysis_signs(design, contrast, mask, signs)
447481
return min_vals, max_vals
448482

449483

examples/fiac/parallel_run.py

Lines changed: 73 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,38 @@
11
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
22
# vi: set ft=python sts=4 ts=4 sw=4 et:
33
"""Script to run the main analyses in parallel, using the IPython machinery.
4+
5+
See ``fiac_example.py``.
46
"""
57
#-----------------------------------------------------------------------------
68
# Imports
79
#-----------------------------------------------------------------------------
810

9-
from IPython.kernel import client
11+
import os
12+
13+
import numpy as np
1014

11-
# Local imports
12-
from fiac_example import GROUP_MASK
15+
from IPython import parallel
1316

1417
#-----------------------------------------------------------------------------
1518
# Utility functions
1619
#-----------------------------------------------------------------------------
1720

18-
def setup_mec():
19-
"""Get a multiengineclient and initialize it.
21+
_client = None
22+
def setup_client():
23+
"""Get a Client and initialize it.
2024
2125
This assumes that all nodes see a shared filesystem.
2226
"""
23-
mec = client.MultiEngineClient()
24-
# Ensure each engine is in the same directory as we are
25-
mydir = os.path.split(os.path.abspath(__file__))[0]
26-
mec.execute('''
27-
import os
28-
os.chdir(%s)
29-
''' % mydir)
30-
return mec
27+
global _client
28+
if _client is None:
29+
_client = parallel.Client()
30+
mydir = os.path.split(os.path.abspath(__file__))[0]
31+
def cd(path):
32+
import os
33+
os.chdir(path)
34+
_client[:].apply_sync(cd, mydir)
35+
return _client
3136

3237

3338
def getruns():
@@ -53,66 +58,72 @@ def getvals():
5358

5459
def fitruns():
5560
"""Run the basic model fit."""
56-
mec = setup_mec()
57-
runs = list(getruns())
58-
mec.scatter('runs', runs)
59-
mec.execute('''
60-
import fiac_example
61-
for subj, run in runs:
62-
try:
63-
fiac_example.run_model(subj, run)
64-
except IOError:
65-
pass
66-
''')
61+
rc = setup_client()
62+
view = rc.load_balanced_view()
63+
i_s, j_s = zip(*getruns())
64+
65+
def _fit(subj, run):
66+
import fiac_example
67+
try:
68+
return fiac_example.run_model(subj, run)
69+
except IOError:
70+
pass
71+
72+
return view.map(_fit, i_s, j_s)
6773

6874

6975
def fitfixed():
7076
"""Run the fixed effects analysis for all subjects."""
71-
mec = setup_mec()
72-
mec.scatter('subjects', range(16))
73-
mec.execute('''
74-
import fiac_example
75-
for s in subjects:
76-
try:
77-
fiac_example.fixed_effects(s, "block")
78-
except IOError:
79-
pass
80-
try:
81-
fiac_example.fixed_effects(s, "event")
82-
except IOError:
83-
pass
84-
''')
77+
rc = setup_client()
78+
view = rc.load_balanced_view()
79+
subjects = range(16)
80+
81+
def _fit(subject):
82+
import fiac_example
83+
try:
84+
fiac_example.fixed_effects(subject, "block")
85+
except IOError:
86+
pass
87+
try:
88+
fiac_example.fixed_effects(subject, "event")
89+
except IOError:
90+
pass
91+
92+
return view.map(_fit, subjects)
8593

8694

8795
def fitgroup():
8896
"""Run the group analysis"""
89-
mec = setup_mec()
90-
group_vals = list( getvals() )
91-
92-
mec.scatter('group_vals', group_vals)
93-
mec.execute('''
94-
import fiac_example
95-
for d, c in group_vals:
96-
fiac_example.group_analysis(d, c)
97-
''')
97+
rc = setup_client()
98+
view = rc.load_balanced_view()
99+
d_s, c_s = zip(*getvals())
100+
101+
def _fit(d, c):
102+
import fiac_example
103+
return fiac_example.group_analysis(d, c)
104+
105+
return view.map(_fit, d_s, c_s)
98106

99107

100108
def run_permute_test(design, contrast, nsample=1000):
101-
mec = setup_mec()
102-
nnod = len(mec.get_ids())
103-
ns_nod = nsample/nnod
104-
mec.push(ns_nod=ns_nod, design=design,contrast=contrast)
105-
mec.execute('''
106-
import fiac_example
107-
from fiac_example import GROUP_MASK
108-
min_vals, max_vals = fiac_example.permutation_test(design, contrast,
109-
GROUP_MASK, ns_nod)
110-
''')
111-
min_vals = mec.gather('min_vals')
112-
max_vals = mec.gather('max_vals')
113-
return min_vals, max_vals
114-
115-
109+
rc = setup_client()
110+
dview = rc[:]
111+
nnod = len(dview)
112+
# Samples per node. Round up
113+
ns_nod = np.ceil(nsample / float(nnod))
114+
115+
def _run_test(n, des, con):
116+
import fiac_example
117+
from fiac_example import GROUP_MASK
118+
min_vals, max_vals = fiac_example.permutation_test(des, con,
119+
GROUP_MASK, n)
120+
return min_vals, max_vals
121+
122+
ar = dview.apply_async(_run_test, ns_nod, design, contrast)
123+
min_vals, max_vals = zip(*[r for r in ar])
124+
return np.concatenate(min_vals), np.concatenate(max_vals)
125+
126+
116127
#-----------------------------------------------------------------------------
117128
# Script entry point
118129
#-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)