| name | interpretable-eeg-biomarkers-parkinsons |
| description | Interpretable EEG biomarkers for Parkinson's disease detection using interpretable electrophysiological features of resting-state EEG. Captures cortical neural dynamics alterations for reliable non-invasive diagnosis and monitoring. Activation: EEG biomarker Parkinson's, interpretable EEG features, resting-state EEG, cortical neural dynamics, PD diagnosis. |
Interpretable EEG Biomarkers for Parkinson's Disease
Interpretable electrophysiological features of resting-state EEG for Parkinson's disease detection and monitoring. Captures reliable cortical neural dynamics alterations for non-invasive clinical applications.
Metadata
- Source: arXiv:2604.01475v2
- Authors: Clinical neuroscience research team
- Published: 2026-04-01
- Category: Clinical Neuroscience, EEG Biomarkers, Parkinson's Disease
Core Methodology
Key Innovation
Parkinson's disease (PD) alters cortical neural dynamics, yet reliable non-invasive electrophysiological biomarkers remain elusive. This framework introduces:
- Interpretable EEG Features: Features with clear neurophysiological meaning rather than black-box deep learning representations
- Resting-State Specificity: Captures disease-related changes in spontaneous brain activity
- Multi-Domain Analysis: Combines spectral, temporal, and connectivity features
- Clinical Reliability: Validated across multiple clinical sites and patient populations
Technical Framework
Feature Categories
1. Spectral Features
- Band-specific power (delta, theta, alpha, beta, gamma)
- Relative power ratios
- Spectral edge frequency
- Peak frequency analysis
2. Temporal Features
- Amplitude envelope fluctuations
- Burst dynamics
- Phase-amplitude coupling
- Event-related desynchronization/synchronization (ERD/ERS)
3. Connectivity Features
- Phase locking value (PLV)
- Weighted phase lag index (wPLI)
- Directed transfer function (DTF)
- Partial directed coherence (PDC)
4. Complexity Features
- Sample entropy
- Lempel-Ziv complexity
- Higuchi's fractal dimension
- Detrended fluctuation analysis (DFA)
Feature Extraction Pipeline
import numpy as np
from scipy import signal
from scipy.stats import entropy
from sklearn.preprocessing import StandardScaler
class EEGFeatureExtractor:
"""
Extract interpretable EEG features for Parkinson's disease detection
"""
def __init__(self, fs=1000, channels=64):
self.fs = fs
self.channels = channels
self.bands = {
'delta': (1, 4),
'theta': (4, 8),
'alpha': (8, 13),
'beta': (13, 30),
'gamma_low': (30, 50),
'gamma_high': (50, 100)
}
self.roi_groups = {
'frontal': ['Fp1', 'Fp2', 'F3', 'F4', 'F7', 'F8', 'Fz', 'FC1', 'FC2', , ],
: [, , , , , , ],
: [, , , , ],
: [, , , ],
: [, , ]
}
():
features = {}
features[] = ._extract_spectral_features(eeg_data, channel_names)
features[] = ._extract_temporal_features(eeg_data)
features[] = ._extract_connectivity_features(eeg_data, channel_names)
features[] = ._extract_complexity_features(eeg_data)
features[] = ._extract_roi_features(eeg_data, channel_names)
features
():
spectral = {}
ch_idx, ch_name (channel_names):
ch_data = eeg_data[ch_idx]
freqs, psd = signal.welch(ch_data, fs=.fs, nperseg=.fs*)
band, (low, high) .bands.items():
mask = (freqs >= low) & (freqs < high)
band_power = np.trapz(psd[mask], freqs[mask])
spectral[] = band_power
total_power = np.trapz(psd, freqs)
spectral[] = total_power
cumsum = np.cumsum(psd) / total_power
sef95 = freqs[np.argmax(cumsum >= )]
spectral[] = sef95
alpha_mask = (freqs >= ) & (freqs <= )
psd[alpha_mask].() > :
peak_freq = freqs[alpha_mask][np.argmax(psd[alpha_mask])]
spectral[] = peak_freq
ch_name channel_names:
alpha = spectral.get(, )
theta = spectral.get(, )
beta = spectral.get(, )
theta > :
spectral[] = alpha / theta
beta > :
spectral[] = alpha / beta
spectral
():
connectivity = {}
n_channels = (channel_names)
plv_matrix = np.zeros((n_channels, n_channels))
band, (low, high) .bands.items():
sos = signal.butter(, [low, high], btype=, fs=.fs, output=)
filtered = signal.sosfilt(sos, eeg_data, axis=)
analytic = signal.hilbert(filtered, axis=)
phases = np.angle(analytic)
i (n_channels):
j (i+, n_channels):
phase_diff = phases[i] - phases[j]
plv = np.(np.mean(np.exp( * phase_diff)))
plv_matrix[i, j] = plv
plv_matrix[j, i] = plv
connectivity[] = np.mean(plv_matrix[np.triu_indices_from(plv_matrix, k=)])
connectivity[] = np.std(plv_matrix[np.triu_indices_from(plv_matrix, k=)])
roi, roi_channels .roi_groups.items():
roi_indices = [channel_names.index(ch) ch roi_channels ch channel_names]
(roi_indices) > :
roi_plv = plv_matrix[np.ix_(roi_indices, roi_indices)]
connectivity[] = np.mean(roi_plv[np.triu_indices_from(roi_plv, k=)])
connectivity
():
temporal = {}
band, (low, high) [(, (, )), (, (, ))]:
sos = signal.butter(, [low, high], btype=, fs=.fs, output=)
filtered = signal.sosfilt(sos, eeg_data, axis=)
envelope = np.(signal.hilbert(filtered, axis=))
threshold = envelope.mean(axis=, keepdims=) + envelope.std(axis=, keepdims=)
bursts = envelope > threshold
temporal[] = np.mean([np.mean(np.diff(np.where(ch)[]))
ch bursts])
temporal[] = np.mean([np.(np.diff(np.where(ch)[]) > )
ch bursts])
temporal[] = np.std(envelope, axis=).mean()
temporal
():
complexity = {}
ch_idx (eeg_data.shape[]):
ch_data = eeg_data[ch_idx]
complexity[] = ._sample_entropy(ch_data, order=, r=)
complexity[] = ._lempel_ziv(ch_data)
complexity[] = ._higuchi_fd(ch_data)
complexity
():
roi = {}
roi_indices = {}
roi_name, roi_channels .roi_groups.items():
indices = [channel_names.index(ch) ch roi_channels ch channel_names]
indices:
roi_indices[roi_name] = indices
band, (low, high) .bands.items():
sos = signal.butter(, [low, high], btype=, fs=.fs, output=)
filtered = signal.sosfilt(sos, eeg_data, axis=)
roi_name, indices roi_indices.items():
roi_power = np.mean([np.var(filtered[i]) i indices])
roi[] = roi_power
roi_indices:
frontal_indices = roi_indices[]
left_frontal = [i i, ch (channel_names)
ch [, , , ]]
right_frontal = [i i, ch (channel_names)
ch [, , , ]]
left_frontal right_frontal:
sos = signal.butter(, [, ], btype=, fs=.fs, output=)
filtered = signal.sosfilt(sos, eeg_data, axis=)
left_power = np.mean([np.var(filtered[i]) i left_frontal])
right_power = np.mean([np.var(filtered[i]) i right_frontal])
roi[] = np.log(right_power) - np.log(left_power)
roi
():
N = (signal)
r = r * np.std(signal)
():
x = np.array([signal[i:i+m] i (N - m + )])
C = np.(np.(np.(x[:, ] - x[, :]), axis=) < r, axis=) / (N - m + )
np.(np.log(C)) / (N - m + )
_phi(order) - _phi(order + )
():
median = np.median(signal)
binary = (signal > median).astype()
n = (binary)
i, c, l = , ,
i + l < n:
binary[i:i+l] == binary[c:c+l]:
l +=
:
i = c
c += l
l =
l != :
c +=
c * np.log2(n) / n
():
N = (signal)
L = []
x = np.arange(, k_max + )
k (, k_max + ):
L_m = []
m (, k + ):
L_m_k = np.([np.(signal[m + i*k - ] - signal[m + (i-)*k - ])
i (, ((N - m) / k))])
L_m_k = L_m_k * (N - ) / (((N - m) / k) * k)
L_m.append(L_m_k)
L.append(np.mean(L_m))
log_x = np.log(x)
log_L = np.log(L)
slope, _ = np.polyfit(log_x, log_L, )
-slope
Interpretable Classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
import shap
class InterpretablePDClassifier:
"""
Interpretable classifier for Parkinson's disease detection
"""
def __init__(self, feature_names):
self.feature_names = feature_names
self.rf = RandomForestClassifier(
n_estimators=100,
max_depth=5,
min_samples_leaf=10,
random_state=42
)
self.lr = LogisticRegression(
penalty='l1',
C=1.0,
solver='saga',
max_iter=1000
)
def fit(self, X, y):
"""Train models with feature importance analysis"""
self.rf.fit(X, y)
self.lr.fit(X, y)
self.explainer = shap.TreeExplainer(self.rf)
self.shap_values = self.explainer.shap_values(X)
return self
def get_top_features():
importance = pd.DataFrame({
: .feature_names,
: .rf.feature_importances_,
: np.(.lr.coef_[])
})
importance[] = (importance[] / importance[].() +
importance[] / importance[].()) /
importance.nlargest(n, )
():
shap_values = .explainer.shap_values(X_instance.reshape(, -))
plt.figure(figsize=(, ))
shap.summary_plot(
shap_values,
X_instance.reshape(, -),
feature_names=.feature_names,
show=
)
plt.tight_layout()
plt
Applications
- PD Diagnosis: Non-invasive screening for early Parkinson's detection
- Disease Monitoring: Track progression and treatment response
- Differential Diagnosis: Distinguish PD from other parkinsonian syndromes
- Biomarker Discovery: Identify novel neural signatures of PD
- Clinical Trials: Objective endpoint for therapeutic trials
Pitfalls
- Medication Effects: Dopaminergic medications alter EEG signatures
- Age Confounds: Age-related EEG changes must be accounted for
- Comorbidities: Depression, anxiety affect EEG patterns
- Movement Artifacts: Patient tremor can contaminate recordings
- Individual Variability: Large inter-individual differences require careful normalization
Related Skills
- brain-network-controllability
- eeg-structure-guided-diffusion
- geometric-brain-dynamics-mapping
- multi-view-o-information-brain-dynamics
References
@article{eegpd2026,
title={Interpretable Electrophysiological Features of Resting-State EEG Capture Parkinson's Disease},
author={[Authors]},
journal={arXiv preprint arXiv:2604.01475},
year={2026}
}