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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
| import numpy as np from sklearn.linear_model import LogisticRegression from sklearn.model_selection import cross_val_score
class TimeResolvedMVPA: """ 时间分辨多变量模式分析 论文核心方法:在毫秒级时间精度上解码认知负荷状态 使用滑动窗口对每个时间点训练分类器 """ def __init__(self, n_timepoints: int = 500, window_ms: int = 100, step_ms: int = 10): """ Args: n_timepoints: 总时间点数(采样率×时长) window_ms: 解码窗口长度(毫秒) step_ms: 步长(毫秒) """ self.window_samples = int(window_ms * 500 / 1000) self.step_samples = int(step_ms * 500 / 1000) self.classifiers = [] self.time_centers = [] def fit(self, eeg_data: np.ndarray, labels: np.ndarray): """ 训练时序解码器 Args: eeg_data: [n_trials, n_timepoints] EEG信号 labels: [n_trials] 0=低负荷, 1=高负荷 Returns: self """ n_trials, n_timepoints = eeg_data.shape for t in range(0, n_timepoints - self.window_samples, self.step_samples): window = eeg_data[:, t:t+self.window_samples] features = self._extract_features(window) clf = LogisticRegression( C=1.0, penalty='l2', solver='lbfgs', max_iter=1000 ) clf.fit(features, labels) self.classifiers.append(clf) self.time_centers.append(t + self.window_samples // 2) return self def _extract_features(self, window: np.ndarray) -> np.ndarray: """ 从EEG窗口提取特征 Args: window: [n_trials, n_samples] Returns: features: [n_trials, n_features] """ mean = np.mean(window, axis=1, keepdims=True) std = np.std(window, axis=1, keepdims=True) skew = self._skewness(window) fft = np.fft.rfft(window, axis=1) power = np.abs(fft) ** 2 freqs = np.fft.rfftfreq(window.shape[1], d=1/500) theta_mask = (freqs >= 4) & (freqs <= 8) theta_power = np.sum(power[:, theta_mask], axis=1, keepdims=True) alpha_mask = (freqs >= 8) & (freqs <= 13) alpha_power = np.sum(power[:, alpha_mask], axis=1, keepdims=True) beta_mask = (freqs >= 13) & (freqs <= 30) beta_power = np.sum(power[:, beta_mask], axis=1, keepdims=True) theta_alpha_ratio = theta_power / (alpha_power + 1e-8) features = np.hstack([ mean, std, skew, theta_power, alpha_power, beta_power, theta_alpha_ratio ]) return features def _skewness(self, x: np.ndarray) -> np.ndarray: """计算偏度""" mean = np.mean(x, axis=1, keepdims=True) std = np.std(x, axis=1, keepdims=True) return np.mean(((x - mean) / (std + 1e-8)) ** 3, axis=1, keepdims=True) def decode_accuracy(self, eeg_data: np.ndarray, labels: np.ndarray) -> list: """ 计算每个时间点的解码准确率 Returns: accuracies: 每个时间点的解码准确率列表 """ accuracies = [] for i, clf in enumerate(self.classifiers): t = i * self.step_samples window = eeg_data[:, t:t+self.window_samples] features = self._extract_features(window) acc = cross_val_score(clf, features, labels, cv=5, scoring='accuracy').mean() accuracies.append(acc) return accuracies
if __name__ == "__main__": np.random.seed(42) n_trials = 100 n_timepoints = 500 * 30 low_load = np.random.randn(n_trials//2, n_timepoints) * 0.5 low_load += 2.0 * np.sin(2 * np.pi * 10 * np.arange(n_timepoints) / 500) high_load = np.random.randn(n_trials//2, n_timepoints) * 0.7 high_load += 3.0 * np.sin(2 * np.pi * 6 * np.arange(n_timepoints) / 500) eeg_data = np.vstack([low_load, high_load]) labels = np.array([0]*(n_trials//2) + [1]*(n_trials//2)) decoder = TimeResolvedMVPA( n_timepoints=n_timepoints, window_ms=100, step_ms=50 ) decoder.fit(eeg_data, labels) accuracies = decoder.decode_accuracy(eeg_data, labels) print(f"时间点数: {len(accuracies)}") print(f"峰值准确率: {max(accuracies):.2%}") print(f"平均准确率: {np.mean(accuracies):.2%}") print(f"检测延迟(首次>55%): {next((i*50 for i, a in enumerate(accuracies) if a > 0.55), 'N/A')}ms")
|