CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
baseline.py225 linesDownload Raw Back to mne
1"""Utility functions to baseline-correct data."""2 3# Authors: The MNE-Python contributors.4# License: BSD-3-Clause5# Copyright the MNE-Python contributors.6 7import numpy as np8 9from .utils import _check_option, _validate_type, logger, verbose10 11 12def _log_rescale(baseline, mode="mean"):13    """Log the rescaling method."""14    if baseline is not None:15        _check_option(16            "mode",17            mode,18            ["logratio", "ratio", "zscore", "mean", "percent", "zlogratio"],19        )20        msg = f"Applying baseline correction (mode: {mode})"21    else:22        msg = "No baseline correction applied"23    return msg24 25 26@verbose27def rescale(data, times, baseline, mode="mean", copy=True, picks=None, verbose=None):28    """Rescale (baseline correct) data.29 30    Parameters31    ----------32    data : array33        It can be of any shape. The only constraint is that the last34        dimension should be time.35    times : 1D array36        Time instants is seconds.37    %(baseline_rescale)s38    mode : 'mean' | 'ratio' | 'logratio' | 'percent' | 'zscore' | 'zlogratio'39        Perform baseline correction by40 41        - subtracting the mean of baseline values ('mean')42        - dividing by the mean of baseline values ('ratio')43        - dividing by the mean of baseline values and taking the log44          ('logratio')45        - subtracting the mean of baseline values followed by dividing by46          the mean of baseline values ('percent')47        - subtracting the mean of baseline values and dividing by the48          standard deviation of baseline values ('zscore')49        - dividing by the mean of baseline values, taking the log, and50          dividing by the standard deviation of log baseline values51          ('zlogratio')52 53    copy : bool54        Whether to return a new instance or modify in place.55    picks : list of int | None56        Data to process along the axis=-2 (None, default, processes all).57    %(verbose)s58 59    Returns60    -------61    data_scaled: array62        Array of same shape as data after rescaling.63    """64    if copy:65        data = data.copy()66    if verbose is not False:67        msg = _log_rescale(baseline, mode)68        logger.info(msg)69    if baseline is None or data.shape[-1] == 0:70        return data71 72    bmin, bmax = baseline73    if bmin is None:74        imin = 075    else:76        imin = np.where(times >= bmin)[0]77        if len(imin) == 0:78            raise ValueError(79                f"bmin is too large ({bmin}), it exceeds the largest time value"80            )81        imin = int(imin[0])82    if bmax is None:83        imax = len(times)84    else:85        imax = np.where(times <= bmax)[0]86        if len(imax) == 0:87            raise ValueError(88                f"bmax is too small ({bmax}), it is smaller than the smallest time "89                "value"90            )91        imax = int(imax[-1]) + 192    if imin >= imax:93        raise ValueError(94            f"Bad rescaling slice ({imin}:{imax}) from time values {bmin}, {bmax}"95        )96 97    # technically this is inefficient when `picks` is given, but assuming98    # that we generally pick most channels for rescaling, it's not so bad99    mean = np.mean(data[..., imin:imax], axis=-1, keepdims=True)100 101    if mode == "mean":102 103        def fun(d, m):104            d -= m105 106    elif mode == "ratio":107 108        def fun(d, m):109            d /= m110 111    elif mode == "logratio":112 113        def fun(d, m):114            d /= m115            np.log10(d, out=d)116 117    elif mode == "percent":118 119        def fun(d, m):120            d -= m121            d /= m122 123    elif mode == "zscore":124 125        def fun(d, m):126            d -= m127            d /= np.std(d[..., imin:imax], axis=-1, keepdims=True)128 129    elif mode == "zlogratio":130 131        def fun(d, m):132            d /= m133            np.log10(d, out=d)134            d /= np.std(d[..., imin:imax], axis=-1, keepdims=True)135 136    if picks is None:137        fun(data, mean)138    else:139        for pi in picks:140            fun(data[..., pi, :], mean[..., pi, :])141    return data142 143 144def _check_baseline(baseline, times, sfreq, on_baseline_outside_data="raise"):145    """Check if the baseline is valid and adjust it if requested.146 147    ``None`` values inside ``baseline`` will be replaced with ``times[0]`` and148    ``times[-1]``.149 150    Parameters151    ----------152    baseline : array-like, shape (2,) | None153        Beginning and end of the baseline period, in seconds. If ``None``,154        assume no baseline and return immediately.155    times : array156        The time points.157    sfreq : float158        The sampling rate.159    on_baseline_outside_data : 'raise' | 'info' | 'adjust'160        What to do if the baseline period exceeds the data.161        If ``'raise'``, raise an exception (default).162        If ``'info'``, log an info message.163        If ``'adjust'``, adjust the baseline such that it is within the data range.164 165    Returns166    -------167    (baseline_tmin, baseline_tmax) | None168        The baseline with ``None`` values replaced with times, and with adjusted times169        if ``on_baseline_outside_data='adjust'``; or ``None``, if ``baseline`` is170        ``None``.171    """172    if baseline is None:173        return None174 175    _validate_type(baseline, "array-like")176    baseline = tuple(baseline)177 178    if len(baseline) != 2:179        raise ValueError(180            f"baseline must have exactly two elements (got {len(baseline)})."181        )182 183    tmin, tmax = times[0], times[-1]184    tstep = 1.0 / float(sfreq)185 186    # check default value of baseline and `tmin=0`187    if baseline == (None, 0) and tmin == 0:188        raise ValueError(189            "Baseline interval is only one sample. Use `baseline=(0, 0)` if this is "190            "desired."191        )192 193    baseline_tmin, baseline_tmax = baseline194 195    if baseline_tmin is None:196        baseline_tmin = tmin197    baseline_tmin = float(baseline_tmin)198 199    if baseline_tmax is None:200        baseline_tmax = tmax201    baseline_tmax = float(baseline_tmax)202 203    if baseline_tmin > baseline_tmax:204        raise ValueError(205            f"Baseline min ({baseline_tmin}) must be less than baseline max ("206            f"{baseline_tmax})"207        )208 209    if (baseline_tmin < tmin - tstep) or (baseline_tmax > tmax + tstep):210        msg = (211            f"Baseline interval [{baseline_tmin}, {baseline_tmax}] s is outside of "212            f"epochs data [{tmin}, {tmax}] s. Epochs were probably cropped."213        )214        if on_baseline_outside_data == "raise":215            raise ValueError(msg)216        elif on_baseline_outside_data == "info":217            logger.info(msg)218        elif on_baseline_outside_data == "adjust":219            if baseline_tmin < tmin - tstep:220                baseline_tmin = tmin221            if baseline_tmax > tmax + tstep:222                baseline_tmax = tmax223 224    return baseline_tmin, baseline_tmax225 
Aluode/PerceptionLabPortable · CoolFace