First level analysis for continuous variable

Hi everyone,

I’m new to fMRI analysis and I’m working on my first dataset. I’d like to test whether a continuous self-report score is associated with the BOLD signal.

I’m using Nilearn’s first-level GLM. The typical workflow uses make_first_level_design_matrix(), which expects an events table with a trial_type column to define conditions/contrasts. In my case, however, I don’t have discrete experimental conditions; instead, I have a continuous rating/score [per trial], and I want to model its relationship with the BOLD response.

From what I understand, this should not be treated as a parametric modulator. I found suggestions to use compute_regressor() to build such a regressor manually, but I’m not sure whether my implementation is correct or whether there is a more idiomatic way in Nilearn.

   func_img = image.load_img(func_file, dtype=np.float32)
    beh_data = pd.read_csv(beh_file, sep="\t")
    confound_data = pd.read_csv(confound_file, sep="\t")
    n_volumes = func_img.shape[-1]
    frame_times = np.arange(n_volumes)
    
    beh_data.rename(columns={"ConfTime": "onset"}, inplace=True)
    beh_data["duration"] = 0
    behavior_vars = ["ConfRating", "Correct", "Difficulty"]
    regressors_dict = {}
    for var_name in behavior_vars:      
        regressor, reg_names = glm.first_level.compute_regressor(
            exp_condition=(
                beh_data["onset"].values.astype(float),
                beh_data["duration"].values.astype(float),
                beh_data[var_name].values.astype(float),
            ),
            hrf_model="spm",
            frame_times=frame_times,
            oversampling=100
        )
        regressors_dict[var_name] = regressor.flatten()
    reg_df = pd.DataFrame(data=regressors_dict, index=frame_times)
    combined_regs = pd.concat([confound_data[confound_cols], reg_df], axis=1)
    combined_reg_names = confound_cols + behavior_vars
    design_matrix = glm.first_level.make_first_level_design_matrix(
        frame_times=frame_times,
        events=None,
        hrf_model="spm",
        oversampling=100,
        drift_model=None,
        add_regs=combined_regs,
        add_reg_names=combined_reg_names
    )

just to be sure sure: have you checked at this example that shows how to build a parametric modulation design matrix in nilearn:

Thank you for your reply. Before writing the script, I consulted the Nilearn tutorial on design matrices, as well as discussions within the neurostars community regarding parametric modulation.

As I understand it, parametric modulation is used to model how neural responses within a given experimental condition vary as a function of a continuous numerical variable (e.g., reward trials modulated by reward magnitude, relative to control trials). This approach is not well-suited for studies that focus exclusively on reward values without a corresponding non-reward or control condition.
In other words, I intend for my design matrix to use the parametric modulator as the primary independent variable, without including trial_type as a distinct regressor.

This approach is not well-suited for studies that focus exclusively on reward values without a corresponding non-reward or control condition.

That sounds strange to me. Can you elaborate?

Also you still using compute_regressor with beh_data[var_name] as modulation which is what make_first_level_design_matrix does under the hood anyway:

My understanding of parametric modulation is that a continuous regulatory variable W modulates the BOLD signal intensity associated with a categorical independent variable A. For example, compared with a control condition, painful stimulation elicits stronger activation in the ACC—a typical effect driven by the categorical variable of experimental condition (pain vs. control). In this framework, parametric modulation can be illustrated by subjective pain ratings: incorporating participants’ self-reported pain scores helps better distinguish and refine the BOLD response to pain relative to the control condition (i.e., treatment × rating → BOLD).

However, my current focus is the main effect of pain rating itself (rating → BOLD) rather than treatment. This effect cannot be directly represented in the trial_type column of the design matrix, as trial_type is typically used for condition contrasts rather than continuous regression.

If you include a “rating” trial_type, that includes the continuous value as modulation, I think that you obtain the design you would like to have.
Sorry if I misunderstood.
HTH,
Bertrand

This seems to be consistent with my approach using compute_regressor ()?

        regressor, reg_names = glm.first_level.compute_regressor(
            exp_condition=(
                beh_data["onset"].values.astype(float),
                beh_data["duration"].values.astype(float),
                beh_data[var_name].values.astype(float),
            ),
            hrf_model="spm",
            frame_times=frame_times,
            oversampling=100
        )

can you send me one of the beh_file you are reading from ?

I think that your approach may model each event several times but it’d be easier if I don’t have to mock data to double check it.

Thank you for your patient reply and selfless help. The behavioral data is attached.

beh_data.txt (1.2 KB)