Wire up NARPS (ds001734) fMRI loader - #2
Merged
Merged
Conversation
added 5 commits
August 7, 2026 17:12
Verified the format against the dataset's own files on OpenNeuro rather than memory: task MGT, TR 1.0 s, 4 runs x 64 trials, events.tsv columns (onset, duration, gain, loss, RT, participant_response) with responses strongly/weakly_accept, strongly/weakly_reject, NoResp; participants.tsv group column (equalIndifference / equalRange). docs/narps.md records the mapping onto the framework (accept/reject as the individual outcome, the (gain,loss) gamble as the stimulus key, population acceptance rate as the aggregate), the traps, and an honest statement of NARPS's role. Key point: on gambles the economic baseline dominates the aggregate arm by construction, so NARPS is an individual-level fMRI plumbing check, NOT a brain-beats-behaviour demonstration. Forcing that headline would misrepresent the task.
The neuroimaging-free layer of the NARPS loader: parses events.tsv, binarises participant_response (strongly/weakly_accept -> 1, *_reject -> 0), drops NoResp trials (RT=0 is missing data, not a fast response), keys each gamble by (gain, loss) as e.g. g14_l06, and builds the behaviour block from the economic variables (gain, loss, expected value, |EV|, RT). Also: acceptance_rate_by_gamble computes the population acceptance rate per gamble (the NARPS aggregate outcome), excluding gambles seen by too few subjects. from_events_and_rois assembles fMRI + behaviour blocks from a precomputed trial-by-ROI matrix, reusing FMRILoader; this is the entry point the nilearn .load path will call after extraction. Verified against a real ds001734 events file. No neuroimaging dependency in this layer.
NARPSLoader.load discovers a subject's runs by globbing *_task-MGT_*_events.tsv, matches each to its preprocessed BOLD and confounds by run label (refusing to proceed on a mismatch, since a dropped run misaligns trials against BOLD), then delegates the BOLD -> ROI sphere extraction to FMRILoader and concatenates runs into one fMRI block plus the behaviour block. FMRILoader.load gains an optional per-run `confounds` argument passed to the NiftiSpheresMasker, so motion and physiological regressors are removed from the ROI timeseries. It warns when confounds are omitted rather than treating that as fine: for task fMRI, head motion correlates with events. Recorded in provenance as confounds_regressed. Requires nilearn; exercised by the fixture in the next commit.
tests/narps_fixture.py writes a miniature but format-real NARPS BIDS tree: participants.tsv with a group column, per-run events.tsv with the verified columns and response strings, a small 4-D preprocessed BOLD NIfTI with an affine placing all five default ROIs inside the volume, and a confounds table. An EV-scaled BOLD bump is planted at the NAcc and MPFC voxels so extraction can be checked; consistent with docs/narps.md, no brain-beats-behaviour claim is planted. tests/test_narps.py: 19 tests. The core (parsing, binarisation, NoResp drop, keys, EV, behaviour block, aggregate acceptance rate, format errors) runs everywhere; the BIDS .load tests importorskip nilearn/nibabel and validate real sphere extraction locally, including that the planted NAcc-EV signal is recovered (r>0.5) and that confounds are regressed. Skipped cleanly in a minimal CI env.
load_narps assembles per-subject blocks into an individual-level MultimodalDataset: one row per trial, y_individual is accept vs reject, CV groups by subject. It is built by direct construction rather than the (subject, stimulus) join, because a subject sees each gamble more than once and that join requires unique keys; the fMRI and behaviour blocks are row-aligned by shared event ordering, which is what MultimodalDataset actually needs. Keeping the gamble as the stimulus key also makes the aggregate arm (population acceptance rate per gamble) work. Group filtering is supported and warns when pooling equalIndifference and equalRange for the aggregate arm, since they saw different gamble matrices. scripts/run_narps.py --demo runs the whole path on the synthetic BIDS fixture and checks the honest, recoverable claim: fMRI ROI features predict accept above chance out of fold and survive label permutation. It does NOT assert brain-beats-behaviour, because on gambles the economic baseline dominates. On the fixture: fMRI balanced accuracy 0.80 individually; on the aggregate arm behaviour (0.75) and brain (0.71) are close, behaviour ahead, exactly as docs/narps.md predicts. CI now installs .[dev,fmri] so the NARPS BIDS tests and demo run rather than skip. 119 tests passing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the NARPS mixed-gambles loader as the framework's first fMRI real-data path, built in five small commits for a clean history. Merges on top of the DEAP loader (#1).
The dataset
NARPS (ds001734, Botvinik-Nezer et al. 2019) is a reward-circuit task: on each trial a participant sees a 50/50 gamble with a possible gain and loss and decides whether to accept. That is the anticipatory-affect paradigm the framework's ROIs come from, so it validates the fMRI loader and the NAcc/vmPFC/AIns sphere extraction on real data. Public on OpenNeuro, no licence.
Format verified against the dataset's own files (not memory): task MGT, TR 1.0 s, 4 runs × 64 trials,
events.tsvcolumnsonset, duration, gain, loss, RT, participant_response, responsesstrongly/weakly_accept,strongly/weakly_reject,NoResp;participants.tsvgroupcolumn (equalIndifference / equalRange).The honest framing
NARPS is an individual-level fMRI validation, and the PR is careful not to oversell it. On gambles, acceptance is largely a function of gain/loss through expected value, so the economic baseline forecasts aggregate acceptance almost by construction. So:
docs/narps.mdpredicts.No brain-beats-behaviour headline is asserted anywhere, because gambles are the wrong task for it. That would misrepresent the data.
Commits (incremental)
docs/narps.md+data_sources.md, before any code.NoRespdrop, gamble keys, behaviour block, aggregate acceptance rate. No neuroimaging dependency.NARPSLoader.loaddiscovers runs and delegates BOLD→ROI extraction toFMRILoader; adds optional per-run confound regression toFMRILoader.load.load_narps→MultimodalDataset, group filtering,scripts/run_narps.py --demo, CI wired to install.[fmri]so the BIDS path runs rather than skips.Validation
.[fmri]is installed.run_narps.py --demopasses its recovery checks (fMRI predicts accept above chance, survives permutation).Still needs
The OpenNeuro download to run for real, ideally with fMRIPrep derivatives. The peak-window ROI mean is a stand-in for a first-level GLM (noted in provenance and docs); swap in
nilearn.glm.first_levelbefore reporting.