A introduction tutorial to fMRI decoding

Here is a simple tutorial on decoding with nilearn. It reproduces the Haxby et al.[1] study on a face vs cat discrimination task in a mask of the ventral stream.

This tutorial is meant as an introduction to the various steps of a decoding analysis using Nilearn meta-estimator: nilearn.decoding.Decoder

It is not a minimalistic example, as it strives to be didactic. It is not meant to be copied to analyze new data: many of the steps are unnecessary.

Retrieve and load the fMRI data from the Haxby study

First download the data

The nilearn.datasets.fetch_haxby function will download the Haxby dataset if not present on the disk, in the nilearn data directory. It can take a while to download about 310 Mo of data from the Internet.

from nilearn import datasets

# By default 2nd subject will be fetched
haxby_dataset = datasets.fetch_haxby()
# 'func' is a list of filenames: one for each subject
fmri_filename = haxby_dataset.func[0]

# print basic information on the dataset
print(f"First subject functional nifti images (4D) are at: {fmri_filename}")
[get_dataset_dir] Dataset found in /home/remi/nilearn_data/haxby2001
First subject functional nifti images (4D) are at: /home/remi/nilearn_data/haxby2001/subj2/bold.nii.gz

Visualizing the fMRI volume

One way to visualize a fMRI volume is using nilearn.plotting.plot_epi. We will visualize the previously fetched fMRI data from Haxby dataset.

Because fMRI data are 4D (they consist of many 3D EPI images), we cannot plot them directly using nilearn.plotting.plot_epi (which accepts just 3D input). Here we are using nilearn.image.mean_img to extract a single 3D EPI image from the fMRI data.

from nilearn import plotting
from nilearn.image import mean_img

plotting.view_img(mean_img(fmri_filename, copy_header=True), threshold=None)
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/numpy/core/fromnumeric.py:758: UserWarning: Warning: 'partition' will ignore the 'mask' of the MaskedArray.
  a.partition(kth, axis=axis, kind=kind, order=order)
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(


Feature extraction: from fMRI volumes to a data matrix

These are some really lovely images, but for machine learning we need matrices to work with the actual data. Fortunately, the nilearn.decoding.Decoder object we will use later on can automatically transform Nifti images into matrices. All we have to do for now is define a mask filename.

A mask of the Ventral Temporal (VT) cortex coming from the Haxby study is available:

mask_filename = haxby_dataset.mask_vt[0]

# Let's visualize it, using the subject's anatomical image as a
# background
plotting.plot_roi(mask_filename, bg_img=haxby_dataset.anat[0], cmap="Paired")
plot decoding tutorial
<nilearn.plotting.displays._slicers.OrthoSlicer object at 0x740d255f2ee0>

Load the behavioral labels

Now that the brain images are converted to a data matrix, we can apply machine-learning to them, for instance to predict the task that the subject was doing. The behavioral labels are stored in a CSV file, separated by spaces.

We use pandas to load them in an array.

import pandas as pd

# Load behavioral information
behavioral = pd.read_csv(haxby_dataset.session_target[0], delimiter=" ")
print(behavioral)
     labels  chunks
0      rest       0
1      rest       0
2      rest       0
3      rest       0
4      rest       0
...     ...     ...
1447   rest      11
1448   rest      11
1449   rest      11
1450   rest      11
1451   rest      11

[1452 rows x 2 columns]

The task was a visual-recognition task, and the labels denote the experimental condition: the type of object that was presented to the subject. This is what we are going to try to predict.

conditions = behavioral["labels"]
print(conditions)
0       rest
1       rest
2       rest
3       rest
4       rest
        ...
1447    rest
1448    rest
1449    rest
1450    rest
1451    rest
Name: labels, Length: 1452, dtype: object

Restrict the analysis to cats and faces

As we can see from the targets above, the experiment contains many conditions. As a consequence, the data is quite big. Not all of this data has an interest to us for decoding, so we will keep only fMRI signals corresponding to faces or cats. We create a mask of the samples belonging to the condition; this mask is then applied to the fMRI data to restrict the classification to the face vs cat discrimination.

The input data will become much smaller (i.e. fMRI signal is shorter):

condition_mask = conditions.isin(["face", "cat"])

Because the data is in one single large 4D image, we need to use index_img to do the split easily.

We apply the same mask to the targets

(216,)

Decoding with Support Vector Machine

As a decoder, we use a Support Vector Classifier with a linear kernel. We first create it using by using nilearn.decoding.Decoder.

from nilearn.decoding import Decoder

decoder = Decoder(
    estimator="svc", mask=mask_filename, standardize="zscore_sample"
)

The decoder object is an object that can be fit (or trained) on data with labels, and then predict labels on data without.

We first fit it on the data

/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(

We can then predict the labels from the data

['face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'cat'
 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'face' 'face' 'face'
 'face' 'face' 'face' 'face' 'face' 'face' 'cat' 'cat' 'cat' 'cat' 'cat'
 'cat' 'cat' 'cat' 'cat' 'face' 'face' 'face' 'face' 'face' 'face' 'face'
 'face' 'face' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat'
 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'face' 'face' 'face'
 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face'
 'face' 'face' 'face' 'face' 'face' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat'
 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat'
 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face'
 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'cat' 'cat' 'cat'
 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'face' 'face' 'face' 'face' 'face'
 'face' 'face' 'face' 'face' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat'
 'cat' 'cat' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face'
 'face' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'face'
 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'cat' 'cat' 'cat'
 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat'
 'cat' 'cat' 'cat' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face'
 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face' 'face'
 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat' 'cat']

Note that for this classification task both classes contain the same number of samples (the problem is balanced). Then, we can use accuracy to measure the performance of the decoder. This is done by defining accuracy as the scoring. Let’s measure the prediction accuracy:

print((prediction == conditions).sum() / float(len(conditions)))
1.0

This prediction accuracy score is meaningless. Why?

Measuring prediction scores using cross-validation

The proper way to measure error rates or prediction accuracy is via cross-validation: leaving out some data and testing on it.

Manually leaving out data

Let’s leave out the 30 last data points during training, and test the prediction on these 30 last points:

fmri_niimgs_train = index_img(fmri_niimgs, slice(0, -30))
fmri_niimgs_test = index_img(fmri_niimgs, slice(-30, None))
conditions_train = conditions[:-30]
conditions_test = conditions[-30:]

decoder = Decoder(
    estimator="svc", mask=mask_filename, standardize="zscore_sample"
)
decoder.fit(fmri_niimgs_train, conditions_train)

prediction = decoder.predict(fmri_niimgs_test)

# The prediction accuracy is calculated on the test data: this is the accuracy
# of our model on examples it hasn't seen to examine how well the model perform
# in general.

predicton_accuracy = (prediction == conditions_test).sum() / float(
    len(conditions_test)
)
print(f"Prediction Accuracy: {predicton_accuracy:.3f}")
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(
Prediction Accuracy: 0.767

Implementing a KFold loop

We can manually split the data in train and test set repetitively in a KFold strategy by importing scikit-learn’s object:

from sklearn.model_selection import KFold

cv = KFold(n_splits=5)

for fold, (train, test) in enumerate(cv.split(conditions), start=1):
    decoder = Decoder(
        estimator="svc", mask=mask_filename, standardize="zscore_sample"
    )
    decoder.fit(index_img(fmri_niimgs, train), conditions[train])
    prediction = decoder.predict(index_img(fmri_niimgs, test))
    predicton_accuracy = (prediction == conditions[test]).sum() / float(
        len(conditions[test])
    )
    print(
        f"CV Fold {fold:01d} | "
        f"Prediction Accuracy: {predicton_accuracy:.3f}"
    )
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(
CV Fold 1 | Prediction Accuracy: 0.886
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(
CV Fold 2 | Prediction Accuracy: 0.767
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(
CV Fold 3 | Prediction Accuracy: 0.767
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(
CV Fold 4 | Prediction Accuracy: 0.698
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(
CV Fold 5 | Prediction Accuracy: 0.744

Cross-validation with the decoder

The decoder also implements a cross-validation loop by default and returns an array of shape (cross-validation parameters, n_folds). We can use accuracy score to measure its performance by defining accuracy as the scoring parameter.

n_folds = 5
decoder = Decoder(
    estimator="svc",
    mask=mask_filename,
    standardize="zscore_sample",
    cv=n_folds,
    scoring="accuracy",
)
decoder.fit(fmri_niimgs, conditions)
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(

Cross-validation pipeline can also be implemented manually. More details can be found on scikit-learn website.

Then we can check the best performing parameters per fold.

print(decoder.cv_params_["face"])
{'C': [100.0, 100.0, 100.0, 100.0, 100.0]}

Note

We can speed things up to use all the CPUs of our computer with the n_jobs parameter.

The best way to do cross-validation is to respect the structure of the experiment, for instance by leaving out full runs of acquisition.

The number of the run is stored in the CSV file giving the behavioral data. We have to apply our run mask, to select only cats and faces.

The fMRI data is acquired by runs, and the noise is autocorrelated in a given run. Hence, it is better to predict across runs when doing cross-validation. To leave a run out, pass the cross-validator object to the cv parameter of decoder.

from sklearn.model_selection import LeaveOneGroupOut

cv = LeaveOneGroupOut()

decoder = Decoder(
    estimator="svc", mask=mask_filename, standardize="zscore_sample", cv=cv
)
decoder.fit(fmri_niimgs, conditions, groups=run_label)

print(decoder.cv_scores_)
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(
{'cat': [1.0, 1.0, 1.0, 1.0, 0.9629629629629629, 0.8518518518518519, 0.9753086419753086, 0.40740740740740744, 0.9876543209876543, 1.0, 0.9259259259259259, 0.8765432098765432], 'face': [1.0, 1.0, 1.0, 1.0, 0.9629629629629629, 0.8518518518518519, 0.9753086419753086, 0.40740740740740744, 0.9876543209876543, 1.0, 0.9259259259259259, 0.8765432098765432]}

Inspecting the model weights

Finally, it may be useful to inspect and display the model weights.

Turning the weights into a nifti image

We retrieve the SVC discriminating weights

[[-3.89376546e-02 -1.87166553e-02 -3.23027518e-02 -2.88747605e-02
   4.18696392e-02  1.10743673e-02  1.69997638e-02 -5.50952689e-02
  -1.94204636e-02 -3.51226862e-02  1.08510735e-02 -1.28796933e-02
  -1.54676482e-02 -3.78909591e-02 -3.69167497e-02  2.28086999e-02
   6.56420809e-03 -7.65769482e-03  1.67106277e-02 -8.02144570e-03
   5.29516265e-02 -8.17593474e-02 -6.36992897e-02  2.41325805e-02
   4.59876052e-02 -2.22603188e-02 -1.77307854e-02  2.22198264e-02
  -9.53177674e-03  5.76046698e-02  2.14300872e-02 -9.14225363e-02
   4.03672408e-03 -2.89275813e-02 -3.89030739e-02 -3.35113618e-02
   2.21400282e-03  8.73125329e-03 -3.37416146e-02 -2.41277021e-02
  -6.81648445e-02  1.65407093e-02  2.70783531e-02 -6.56843940e-03
  -1.21664885e-02  5.47674145e-02  8.13279393e-03  3.60953998e-02
  -1.52763335e-02  7.02913499e-02  1.28095712e-03  2.08006387e-02
  -4.09929739e-03  3.72429093e-02 -3.77394447e-02 -1.03858627e-02
  -2.38237495e-02 -5.48880219e-02  4.43026481e-02 -1.47419309e-01
  -2.34042156e-02  1.87114250e-02  6.65859284e-02 -9.07603878e-02
  -1.22034000e-02 -2.95658284e-03  3.22093117e-02 -3.04053574e-02
   6.15344255e-02  1.12249661e-02  1.93774422e-02 -1.30539800e-02
   4.42975642e-02 -2.23065427e-02  6.88146947e-02  1.69389783e-02
   1.78946439e-02  1.00274929e-02  2.99186085e-02 -2.52171871e-02
   1.06153076e-02 -6.31957932e-03  2.21501700e-03 -2.23349603e-02
   1.42560652e-02 -1.53124030e-02 -1.98226928e-02 -4.32637172e-02
  -4.55125528e-02  3.41589569e-02 -2.79199357e-02 -2.80907702e-02
  -3.70159432e-02 -5.71451017e-02 -6.98948616e-02  3.20179213e-03
  -8.35453120e-03 -3.37627406e-02  3.04261216e-02  8.68451715e-03
   6.19389422e-03  5.94179320e-02  9.07292949e-03 -1.48931184e-02
   1.43558939e-02 -1.09027671e-02  2.67698012e-02  4.73786390e-02
  -2.96431303e-02  3.09423340e-02  1.57930565e-02 -3.16721910e-02
  -4.00106634e-02 -5.40262098e-02  2.82613416e-02 -1.12101310e-02
  -5.45402833e-02  6.32177953e-02 -1.49997250e-02  2.47545331e-03
  -4.56644275e-02 -1.83882771e-02  1.19958131e-02 -3.72172161e-02
  -2.25527238e-03  4.58656527e-02  4.79168913e-02  2.51819349e-03
  -4.31720235e-02 -5.35336630e-03  5.76995390e-02  7.40840612e-03
  -3.20590441e-02  4.35707132e-03  1.68303379e-02 -2.92569790e-02
  -2.24494624e-03 -8.30207096e-03 -1.00013637e-02  2.17136196e-02
  -1.92610551e-03 -1.33221845e-02 -2.80300444e-02 -1.75295289e-02
  -9.17805710e-03 -7.09939964e-03 -1.43031750e-02  5.06830540e-02
  -1.84813883e-02 -4.71505044e-02  1.72569416e-02 -4.76640941e-02
  -9.09064901e-04  4.00767614e-02  7.53994834e-02  7.25623064e-03
   4.82604788e-02  4.50554400e-02  3.61201059e-02 -8.16494876e-03
   1.95405535e-02  3.57883695e-02  4.89304833e-02  3.82973189e-02
   6.23919914e-02  6.13675171e-02 -1.68751074e-02  1.66513807e-02
   3.35521582e-02 -1.80212035e-02  4.46411307e-02 -3.53244687e-02
  -3.67293154e-02 -4.62243586e-03  4.86827104e-02  3.39667089e-02
   6.21727263e-03  1.73611732e-02  2.01697197e-02  2.17098036e-02
   2.91412800e-02  2.37777048e-02  4.84699701e-02 -9.22625467e-03
  -2.82637720e-02 -2.13782058e-02  1.80796937e-03  4.79686720e-02
  -9.78905039e-03  1.11431818e-02 -1.65018677e-02 -2.89090568e-02
   2.42850133e-02 -1.22346130e-02 -2.92870743e-02 -2.89843354e-02
  -3.39532749e-02 -3.65262226e-03  2.65325467e-02  4.58045423e-02
  -5.93380688e-02 -2.13630172e-02 -3.09409082e-02  5.50179468e-02
  -3.38815735e-02  6.12597077e-03  1.41484514e-02  1.10215883e-02
   5.33812148e-02 -2.12339471e-02  6.37429792e-03 -1.13075760e-02
  -2.64225015e-02 -2.22399090e-02 -5.31920554e-02 -3.98653148e-02
  -1.29727912e-01 -3.28091488e-02 -2.89713492e-02 -9.13479193e-03
  -7.28727776e-03 -3.71052894e-02 -6.34906744e-02  2.04382589e-03
  -8.26795681e-02 -6.71213980e-02 -2.29122346e-03 -2.33453252e-02
   1.77914842e-02 -8.74667787e-02 -2.76485794e-03 -4.38277200e-02
  -1.28050648e-02  2.78035751e-02 -4.32695430e-02 -3.22687357e-02
  -2.28029217e-02 -2.57415514e-02  2.03623580e-02 -9.90244453e-03
  -3.15033053e-02 -1.81420745e-02 -1.12345401e-03 -4.17431381e-02
  -6.23480887e-02  2.54559574e-04 -6.73679875e-02  6.53966249e-02
   1.06520728e-02  2.21983421e-02 -1.98728188e-02 -1.85519762e-02
   4.05703742e-02 -3.02838792e-02 -8.10051030e-02 -7.42458340e-02
  -4.93846607e-02 -1.01770291e-02  1.09406031e-02 -4.49254939e-02
   2.92747495e-02  7.05305267e-03  5.07528640e-03 -4.84057418e-03
   2.48769275e-03  3.00653820e-02 -2.63081812e-03  4.64686911e-03
   7.90209191e-02  1.04858263e-02  1.68080079e-02 -4.36719304e-02
  -1.08856897e-02  2.10241952e-02 -4.41966273e-02  3.16492517e-03
   6.98669954e-02  8.61627673e-02  4.96236940e-02  6.03904869e-03
   5.56496036e-02 -2.98919027e-02  4.13035003e-03 -3.21950877e-02
  -3.14990197e-02 -5.31274869e-02  2.67257117e-02  3.14429122e-02
   6.67092622e-03 -1.28703365e-02  2.20151261e-02  5.68524277e-02
   2.25603531e-02 -2.04617426e-02  5.10346269e-03  2.85357213e-02
  -1.81664053e-02 -8.48424731e-03 -3.18827284e-02 -1.18497243e-02
  -4.10845932e-02  3.11775004e-02  9.63465863e-03 -8.25906625e-03
  -3.12226451e-02  8.57643183e-03 -9.70201605e-03  1.32373321e-02
   4.06447489e-02  8.23419499e-03 -3.27354701e-02 -4.33894301e-03
  -1.75531671e-02  6.88838561e-03  3.45132805e-02  7.03299083e-02
   2.16784240e-02  5.32233852e-03  8.17563232e-02  6.40062554e-02
  -2.31138606e-03 -1.17558584e-02  1.75889160e-01  3.18130107e-02
  -3.15886757e-02  3.34028460e-02  2.22779840e-02  1.00231632e-02
  -4.74911571e-02 -2.12756041e-02 -3.98718576e-02 -6.04070304e-02
  -4.65060635e-02  1.03004331e-02 -3.05854371e-04  1.80743442e-02
  -1.75451092e-02 -8.72588941e-02  1.00662708e-01  4.46114111e-03
   7.46870146e-02 -6.13412095e-02  2.81704059e-02 -1.40977308e-02
   3.14638244e-02 -1.63834199e-02  3.66533344e-02 -5.15687780e-03
   1.45093641e-02  6.35867333e-02  2.34598454e-02  8.81063250e-02
   6.15344990e-02 -1.39362708e-02  2.07245959e-02 -3.15444082e-03
   5.15425368e-02 -2.88766849e-02  1.60262581e-02  2.09702408e-02
  -3.29173141e-02 -2.59460655e-02 -5.60400217e-02 -3.64627821e-02
   1.12882013e-02  2.17268644e-02 -1.51638886e-02 -7.82890879e-03
   2.42549614e-02  9.47012771e-02 -2.63033850e-02  1.17321272e-04
  -5.24173762e-03  4.17988320e-02  8.85681252e-02  6.23661679e-03
   1.86601070e-02  1.54628842e-02  3.50540654e-03  6.20605033e-03
  -1.19789607e-02  1.59526487e-02  7.12124622e-03 -8.93192037e-02
  -3.54343279e-03  1.23478911e-02  3.03927660e-02 -2.37296030e-02
  -3.82791453e-02 -4.98745365e-02  4.66896674e-02 -1.23291995e-02
  -1.10332591e-02  2.18104952e-02  2.18718210e-02  2.63539358e-02
   1.05280391e-02  1.84617582e-02  8.36122257e-04 -6.65218952e-03
   3.49396426e-02  1.49352983e-02 -1.11598970e-02  6.69098457e-03
  -2.00059298e-02 -3.99015501e-02  3.01872467e-02 -1.09866320e-02
  -4.11781832e-02  2.72053476e-02  1.16426142e-02 -1.55502676e-02
   3.27700860e-02  3.95495131e-02  8.48725040e-03  2.19934933e-02
  -9.88673659e-03 -3.61420362e-02 -4.77021585e-02  1.90076776e-02
  -5.58285421e-02 -3.31739067e-02 -2.24914197e-02 -3.36174076e-02
  -4.07354520e-02  1.08860619e-02  1.12810054e-02  7.63143345e-02
   4.04797061e-03  3.07013654e-02  2.89177100e-02  4.71606766e-03
   5.13385271e-02 -4.10363939e-02  1.23271819e-03 -2.50404004e-02
   5.85904287e-02 -1.04965663e-01 -4.41704933e-02  1.18520383e-02
  -5.83203929e-02 -4.82245092e-02  9.17663770e-03  1.03259430e-02
  -5.09195503e-03 -3.23390616e-02 -3.19388130e-02 -1.53770209e-02
  -5.21211050e-02  1.55620168e-02  2.93484146e-02 -1.92527579e-02
   1.76693884e-02  2.67992082e-02  5.76554031e-02 -1.38163927e-02
   2.60400527e-02  1.50399779e-02  1.27423585e-02 -2.29244294e-02
  -1.06664464e-02  9.81939065e-03 -4.77510946e-02  1.64243510e-02]]

It’s a numpy array with only one coefficient per voxel:

print(coef_.shape)
(1, 464)

To get the Nifti image of these coefficients, we only need retrieve the coef_img_ in the decoder and select the class

coef_img is now a NiftiImage. We can save the coefficients as a nii.gz file:

from pathlib import Path

output_dir = Path.cwd() / "results" / "plot_decoding_tutorial"
output_dir.mkdir(exist_ok=True, parents=True)
print(f"Output will be saved to: {output_dir}")
decoder.coef_img_["face"].to_filename(output_dir / "haxby_svc_weights.nii.gz")
Output will be saved to: /home/remi/github/nilearn/nilearn_doc_build/examples/00_tutorials/results/plot_decoding_tutorial

Plotting the SVM weights

We can plot the weights, using the subject’s anatomical as a background

plotting.view_img(
    decoder.coef_img_["face"],
    bg_img=haxby_dataset.anat[0],
    title="SVM weights",
    dim=-1,
)
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/numpy/core/fromnumeric.py:758: UserWarning: Warning: 'partition' will ignore the 'mask' of the MaskedArray.
  a.partition(kth, axis=axis, kind=kind, order=order)


What is the chance level accuracy?

Does the model above perform better than chance? To answer this question, we measure a score at random using simple strategies that are implemented in the nilearn.decoding.Decoder object. This is useful to inspect the decoding performance by comparing to a score at chance.

Let’s define a object with Dummy estimator replacing ‘svc’ for classification setting. This object initializes estimator with default dummy strategy.

dummy_decoder = Decoder(
    estimator="dummy_classifier",
    mask=mask_filename,
    cv=cv,
    standardize="zscore_sample",
)
dummy_decoder.fit(fmri_niimgs, conditions, groups=run_label)

# Now, we can compare these scores by simply taking a mean over folds
print(dummy_decoder.cv_scores_)
/home/remi/github/nilearn/nilearn_doc_build/.tox/doc/lib/python3.9/site-packages/nilearn/image/resampling.py:526: UserWarning: The provided image has no sform in its header. Please check the provided file. Results may not be as expected.
  warnings.warn(
{'cat': [0.38888888888888895, 0.38888888888888895, 0.38888888888888895, 0.6111111111111112, 0.38888888888888895, 0.6111111111111112, 0.38888888888888895, 0.38888888888888895, 0.38888888888888895, 0.38888888888888895, 0.6111111111111112, 0.38888888888888895], 'face': [0.38888888888888895, 0.38888888888888895, 0.38888888888888895, 0.6111111111111112, 0.38888888888888895, 0.6111111111111112, 0.38888888888888895, 0.38888888888888895, 0.38888888888888895, 0.38888888888888895, 0.6111111111111112, 0.38888888888888895]}

References

See also


Total running time of the script: (0 minutes 42.160 seconds)

Estimated memory usage: 1050 MB

Gallery generated by Sphinx-Gallery