Can I set units manually (to dimensionless) when I Z-score my raw data?

Some of my sEEG channels have unusually high variance but similar patterns of activity as the other lower-variance channels.

An obvious normalization is to Z-score the entire time-course across time to ensure zero mean and unit variance: and this does make the channels’ activity look more normal/comparable, which is nice.

  1. I can’t do this baselining either on the mne.io.Raw or the mne.Epochs objects automatically, because they only support mode="mean". So I ended up using the .apply_function() method to Z-score each channel:
def normalize_raw_data(
    raw: mne.io.BaseRaw,
    *,
    mode: Literal["zscore", "mean"] | None = "zscore",
) -> mne.io.BaseRaw:
    match mode:
        case "zscore":
            return raw.load_data().apply_function(
                lambda x: (
                    (x - x.mean(axis=-1, keepdims=True)) / x.std(axis=-1, keepdims=True)
                    if ~np.any(x.std(axis=-1, keepdims=True) == 0)
                    else x
                ),
                channel_wise=True,
            )
        case "mean":
            return raw.load_data().apply_function(
                lambda x: x - x.mean(axis=-1, keepdims=True),
                channel_wise=True,
            )
        case None:
            return raw
        case _:
            raise ValueError
  1. But this approach messes up the expected units of these classes: they are now dimensionless but I can’t specify that in either mne.io.Raw or mne.Epochs—they assume that the data is stored in volts.

Is there any recommended way to proceed?

I’m not particularly upset about this—I just need to adjust scalings manually when plotting and ignore the “V” units that are assumed and thrown in in several places.

But I imagine this should be a common normalization? Is there a particular reason this use-case isn’t supported beyond making the code more complicated (which is totally valid lol, no shade)?

I’m relatively new to EEG data analysis, but coming from a signal processing/ML/fMRI background, I’m used to early transformations/normalizations of the data before downstream analyses.

Hi @Snore2338, MNE doesn’t really support “dimensionless” for standard data channels because it breaks the metadata expectations of the Info object.
Well it depends on your use-case, for viz plots ig a common trick is to temporarily set the channel types to ‘misc’.
However, for ML tasks, mne.decoding.Scaler would work to Z-score without breaking the Raw object’s metadata.