eegproc.preprocessing module
- eegproc.preprocessing.apply_detrend(detrend, df)[source]
Apply interpolation and (optionally) remove a trend from each numeric column.
This is a small convenience wrapper that first ensures numeric columns are float and linearly interpolated (forward/backward) via
numeric_interp(), then, depending ondetrend, optionally removes a trend from each column usingdetrend_df().- Parameters:
detrend (
str|None) – Which trend to remove. Accepted values are: -"constant": remove the mean from each series (demean). -"linear": remove a best-fit linear trend from each series. -None: do not detrend; only interpolate numeric columns.df (
DataFrame) – Input dataframe. Non-numeric columns are ignored for interpolation and detrending (they are effectively dropped by the pipeline).
- Return type:
DataFrame- Returns:
pd.DataFrame – A dataframe with only numeric columns, interpolated, and optionally detrended according to
detrend. Index and column names are preserved for the remaining numeric columns.- Raises:
ValueError – If
detrendis not one of{"constant", "linear", None}.
See also
numeric_interp: Coerces numeric columns to float and bi-directionally interpolates. detrend_df: Applies SciPy detrending (constant or linear) column-wise.
Examples
>>> import pandas as pd, numpy as np >>> df = pd.DataFrame({"a": [1.0, np.nan, 3.0], "b": [10.0, 11.0, np.nan], "c": ["x", "y", "z"]}) >>> apply_detrend("constant", df) # demean numeric columns after interpolation a b 0 -1.000000 -0.5 1 0.000000 0.5 2 1.000000 0.0
>>> apply_detrend(None, df) # only numeric interpolation a b 0 1.0 10.0 1 2.0 11.0 2 3.0 11.0
- eegproc.preprocessing.apply_notch_once(dfin, notch_hz, notch_q, nyq)[source]
Apply single-pass IIR notch filtering (and optional 2x harmonic) to each column to remove narrow amplitude readings over selected frequencies.
Builds one or more IIR notch filters at the requested fundamental frequencies, optionally adding a 2x harmonic notch when it is safely below Nyquist, and applies zero-phase filtering (
scipy.signal.filtfilt,method="gust") column-wise.- Parameters:
dfin (
DataFrame) – Raw data EEG dataframe. Numeric columns.notch_hz (
float|int|list|tuple|None) – Fundamental notch frequency (e.g., 50 or 60), or a list/tuple of such frequencies. IfNone, no notch filtering is applied.notch_q (
float) – Quality factor forscipy.signal.iirnotch(higher = narrower notch).nyq (
float) – Nyquist frequency (fs/2), used to normalize the notch frequency.
- Return type:
DataFrame- Returns:
pandas.DataFrame – Copy of the input with the notch (and eligible 2x harmonic) applied to all columns with sufficient length.
Notes
A 2x harmonic is added for each fundamental
f0when2*f0 < nyq - 1.0.Columns shorter than
max(15, 3 * max(len(a), len(b)))samples are skipped for stability.Frequencies are normalized as
w0 = f0 / nyqforiirnotch.
- eegproc.preprocessing.bandpass_filter(df, fs, bands={'alpha': (8.0, 13.0), 'betaH': (20.0, 30.0), 'betaL': (13.0, 20.0), 'delta': (0.5, 4.0), 'gamma': (30.0, 45.0), 'theta': (4.0, 8.0)}, low=None, high=None, *, order=4, notch_hz=[60, 120], notch_q=30.0, reref=True, detrend=True)[source]
Applies band-pass filtering over raw EEG data on each channel.
Pipeline
Coerce to numeric (with interpolation).
Optional common average reference (CAR) across channels (
reref=True).Optional notch filtering at
notch_hz(and 2x harmonics when safe).
- 4a) If
bandsis a dict: apply a per-band Butterworth band-pass (SOS) and return columns named
{channel}_{band}.- 4b) Else: require
(low, high)and apply a single band-pass to each channel, returning the original channel names.
Optional constant detrending per output column.
- param df:
Raw data EEG dataframe. Numeric columns; NaNs are interpolated internally by
numeric_interpbefore filtering.- type df:
DataFrame- param fs:
Sampling rate in Hz.
- type fs:
float- param bands:
If provided, a mapping from band name to (low, high) in Hz. When given, one output column per
{channel}_{band}is produced. IfNone,lowandhighmust be provided to define a single passband.- type bands:
dict[str,tuple[float,float]], default:{'delta': (0.5, 4.0), 'theta': (4.0, 8.0), 'alpha': (8.0, 13.0), 'betaL': (13.0, 20.0), 'betaH': (20.0, 30.0), 'gamma': (30.0, 45.0)}- param low:
Low cutoff in Hz for the single band-pass path (ignored if
bandsprovided).- type low:
float|None, default:None- param high:
High cutoff in Hz for the single band-pass path (ignored if
bandsprovided).- type high:
float|None, default:None- param order:
Butterworth filter order for band-pass design.
- type order:
int, default:4- param notch_hz:
Fundamental notch frequency/frequencies.
Nonedisables notch filtering.- type notch_hz:
float|int|list|tuple|None, default:[60, 120]- param notch_q:
Quality factor for the notch (higher = narrower).
- type notch_q:
float, default:30.0- param reref:
If True and there are ≥2 channels, apply common average reference (CAR).
- type reref:
bool, default:True- param detrend:
If True, remove the mean (constant detrend) after filtering.
- type detrend:
bool, default:True- rtype:
DataFrame- returns:
pandas.DataFrame – Filtered dataframe indexed like the input. If
bandsis provided, columns are{channel}_{band}; otherwise, the original channel names are preserved.- raises ValueError:
When
bandsisNoneand eitherloworhighis missing. - When any cutoff does not satisfy0 < low < high < fs/2. - When a band inbandsviolates Nyquist constraints.
Warning
- RuntimeWarning
Emitted when
reref=Truebut only one channel is present (CAR requires ≥2).
Notes
Band-pass filters are designed with
scipy.signal.butter(..., output="sos")and applied with a NaN-robust zero-phase filter via_sosfiltfilt_safe().Notch filtering is applied once before band-pass filtering.
Constant detrend uses
scipy.signal.detrend(..., type="constant").For stability, very short columns may be skipped inside helper routines.
- eegproc.preprocessing.numeric_interp(df)[source]
Select numeric columns, cast to float, and interpolate missing values.
- The function:
keeps only numeric dtypes,
casts them to
float(to allow NaNs and interpolation),fills missing values with linear interpolation along the index, using
limit_direction='both'to also fill leading/trailing gaps.
Non-numeric columns are dropped.
- Parameters:
df (
DataFrame) – Input dataframe containing numeric and/or non-numeric columns.- Return type:
DataFrame- Returns:
pd.DataFrame – A copy containing only the numeric columns as floats, with missing values linearly interpolated forward and backward.
Notes
Interpolation is performed independently per column.
If a column is entirely NaN, it will remain NaN.
Examples
>>> import pandas as pd, numpy as np >>> df = pd.DataFrame({"x": [1.0, np.nan, 3.0], "y": ["a", "b", "c"]}) >>> numeric_interp(df) x 0 1.0 1 2.0 2 3.0
- eegproc.preprocessing.sosfiltfilt_safe(sos, y)[source]
Zero-phase Second-order Section (SOS) filter, handles NaNs and short signals.
Applies
scipy.signal.sosfiltfiltto a 1-D array. Linearly interpolates internal NaNs (or fills with 0.0 if too few finite samples to interpolate).- Parameters:
sos (array-like) – Second-order-sections filter coefficients as produced by
scipy.signal.butter(..., output="sos").y (array-like of shape (n_samples,)) – Input signal (1-D). May contain NaNs.
- Returns:
numpy.ndarray – Filtered signal. If the input is all-NaN or too short, returns a copy of the input (with NaNs interpolated when possible).
Notes
NaNs at the edges are handled by linear interpolation using the nearest finite samples when available; otherwise they are set to 0.0.
The minimum-length guard (15) prevents filtfilt endpoint artifacts and poor padding when the window is too small.