Correlate ICA to external lip electrodes

Hello,

I am trying to calculate correlations between ICA components and external electrodes placed on the upper and lower lip of a participant.

Thus far, I have extracted the components as an array, and the raw data reduced to the electrodes with which I want to calculate the correlation. I am rather stuck with how to proceed, however.

My thinking here is to use either np.correlate or np.corrcoef, though I don’t know which, if either, is appropriate. The end goal is to find those ICA components which most highly correlate with activity in these external electrodes so that they might be excluded from the raw signal. I wonder if what I’m hoping to achieve is similar to the EOG, ECG, or EMG detection procedures outlined in the examples given online.

I haven’t worked out how to adapt Annotate muscle artifacts — MNE 1.8.0 documentation or Removing muscle ICA components — MNE 1.8.0 documentation to my problem, and perhaps there is something there I’ve overlooked.

The code snippet below is a rough overview of what I have attempted.

import mne
import numpy as np

raw = mne.io.read_raw_fif(subjects[0])
ica = mne.preprocessing.read_ica(ica_fits[0])

lip_electrodes = raw.copy().pick(["upper_lip", "lower_lip"])

lip_data = lip_electrodes.get_data()
ica_data = ica.get_components()

upper_lip_data = lip_data[0]
lower_lip_data = lip_data[1]

ica_data_flat = ica_data.flatten()

np.correlate(upper_lip_data, ica_data_flat)

MNE version: 1.8.0
OS: macOS 15.1.1

Hi,

Computing correlation

For correlating the lip and ICA component activity, np.corrcoef would work. Here’s an example based on your provided code:

# Compute Pearson correlation
corr = np.corrcoef(lip_data, ica_data)

# Extract seed-target connectivity
n_lip_chans = lip_data.shape[0]
con = corr[:n_lip_chans, n_lip_chans:]  # shape (lip chans x ica comps)

The corrcoef function returns a large matrix that can be divided into 4 quadrants:

  • upper left - lip to lip connectivity
  • upper right - lip to ICA connectivity
  • lower left - ICA to lip connectivity
  • lower right - ICA to ICA connectivity

The code extracts this upper right lip to ICA connectivity information (but since this correlation is a non-directed connectivity measure, the upper right and lower left quadrants contain the same information).

What con gives you is a set of connectivity values between each of your lip channels and ICA components in the range [-1, 1]. -1 means a perfect negative correlation, +1 a perfect positive correlation. If the direction of correlation is not of interest, you could just take the absolute values to get scores in the range [0, 1] (i.e., no correlation, perfect correlation).

Removing artefacts

I have never worked with lip electrode data, so this I am less sure about.

I’m not sure what cutoff for the correlation values should be used to say that a given component represents the lip data. In any case you should try corroborating this visually.
In your ICA components, if you visually inspect them do you see any components that resemble the activity of the lip electrodes? Are there some stereotypical lip artefacts that can be seen like the blink artefacts in ICA000 of the first plot in this example? Somehow I doubt it might be so clear.

Perhaps a regression approach like for EOG would work better like you see in this example. You would just need to make sure that when you perform the regression with the EOGRegression class that you specify the picks_artifact parameter to be you lip channels rather than the default EOG.

See also this longer tutorial if you want more information on the regression approach.

Sorry I can’t provide a more concrete answer, you may have to test a couple approaches.

Cheers,
Thomas

2 Likes

Hi Thomas,

Thank you so much for this thorough response. I’ve just taken the first crack at your solution:

I received the following error:

ValueError: all the input array dimensions except for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 1978368 and the array at index 1 has size 55

The array dimensions are as follows:

lip_data.shape  # (1, 1978368)
ica_data.shape  # (126, 55)

How might I best make these arrays play nicely together?

Cheers,
Alec

Hi,

you should use ica.get_sources(raw) to obtain the time courses of ica components instead of get_components(), which gives you spatial distribution.

Best regards.

2 Likes

Ah sorry @alecshaw, I didn’t read your code snippet properly.
Yes, you will need the time courses of the components as @Contamior pointed out.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.