1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
| import numpy as np from scipy.signal import welch from sklearn.preprocessing import StandardScaler
class UnifiedEEGFeatureExtractor: """ 统一EEG特征提取框架 目标: 提取跨被试通用的EEG特征 策略: 组合多域特征 + 个体归一化 """ def __init__(self, sample_rate=250): self.fs = sample_rate self.bands = { "delta": (0.5, 4), "theta": (4, 8), "alpha": (8, 13), "beta": (13, 30), "gamma": (30, 45) } def extract_all_features(self, eeg_data, channels=None): """ 提取多域特征 Args: eeg_data: EEG数据 (channels, time) 或 (trials, channels, time) Returns: features: 统一特征向量 """ if eeg_data.ndim == 2: eeg_data = eeg_data[np.newaxis, ...] n_trials, n_channels, n_samples = eeg_data.shape all_features = [] for trial in eeg_data: time_features = self._time_domain(trial) freq_features = self._frequency_domain(trial) tf_features = self._time_frequency(trial) combined = np.concatenate([time_features, freq_features, tf_features]) normalized = self._normalize_individual(combined) all_features.append(normalized) return np.array(all_features) def _time_domain(self, trial): """时域特征""" features = [] for ch in trial: activity = np.var(ch) mobility = np.sqrt(np.var(np.diff(ch)) / (activity + 1e-10)) complexity = np.sqrt( np.var(np.diff(np.diff(ch))) / (np.var(np.diff(ch)) + 1e-10) ) / (mobility + 1e-10) features.extend([ activity, mobility, complexity, np.mean(ch), np.std(ch), np.sqrt(np.mean(ch**2)), np.mean(np.abs(ch)), ]) return np.array(features) def _frequency_domain(self, trial): """频域特征""" features = [] for ch in trial: freqs, psd = welch(ch, self.fs, nperseg=128) band_powers = [] for band, (low, high) in self.bands.items(): mask = (freqs >= low) & (freqs < high) power = np.trapz(psd[mask], freqs[mask]) band_powers.append(power) band_powers = np.array(band_powers) total_power = np.sum(band_powers) + 1e-10 theta_alpha = band_powers[1] / (band_powers[2] + 1e-10) beta_alpha = band_powers[3] / (band_powers[2] + 1e-10) rel_powers = band_powers / total_power features.extend(band_powers) features.extend(rel_powers) features.extend([theta_alpha, beta_alpha]) return np.array(features) def _time_frequency(self, trial): """时频域特征 (简化版)""" n_segments = 4 seg_len = trial.shape[1] // n_segments tf_features = [] for ch in trial: for seg in range(n_segments): segment = ch[seg*seg_len:(seg+1)*seg_len] _, psd = welch(segment, self.fs, nperseg=min(64, len(segment))) alpha_mask = (np.arange(len(psd)) * self.fs / 128 >= 8) & \ (np.arange(len(psd)) * self.fs / 128 < 13) alpha_power = np.trapz(psd[alpha_mask]) if np.any(alpha_mask) else 0 tf_features.append(alpha_power) return np.array(tf_features) def _normalize_individual(self, features): """个体归一化: 减少被试间基线差异""" return (features - np.mean(features)) / (np.std(features) + 1e-10)
extractor = UnifiedEEGFeatureExtractor()
fake_eeg = np.random.randn(14, 2500) features = extractor.extract_all_features(fake_eeg) print(f"EEG数据: {fake_eeg.shape}") print(f"提取特征: {features.shape}")
|