diff --git a/src/preprocessing/spectral_Preprocessing.py b/src/preprocessing/spectral_Preprocessing.py index e75eb0a..8637b4e 100644 --- a/src/preprocessing/spectral_Preprocessing.py +++ b/src/preprocessing/spectral_Preprocessing.py @@ -378,37 +378,48 @@ class MNFTransformer(TransformerMixin, BaseEstimator, _ArrayAsFloat64): def fit(self, X, y=None): X = self._to_ndarray(X) + X = np.nan_to_num(X, nan=0.0, posinf=0.0, neginf=0.0) n_samples, n_features = X.shape - # 1) 噪声矩阵:相邻行差分(假设输入按空间/时间连续排列) + # 1) 噪声矩阵:相邻行差分 noise = X[1:] - X[:-1] # (n-1, p) Cn = np.cov(noise, rowvar=False) # (p, p) - Cn += np.eye(n_features) * 1e-9 # 防止奇异 + # 正则化:按总方差的 1% 加对角项,强于固定 1e-9 + _reg = np.trace(Cn) / n_features * 0.01 + Cn += np.eye(n_features) * max(_reg, 1e-6) - # 2) 噪声白化:Cn = U diag(S) Vt — 对称矩阵用 eigh + # 2) 噪声白化:仅对显著特征值做白化,忽略噪声主导的成分 eigvals_n, eigvecs_n = np.linalg.eigh(Cn) - # eigh 返回升序排列;白化矩阵 = V @ diag(1/sqrt(s)) @ V.T - inv_sqrt = 1.0 / np.sqrt(np.maximum(eigvals_n, 1e-12)) - Wn = eigvecs_n @ np.diag(inv_sqrt) @ eigvecs_n.T # (p, p) + # 截断:特征值 < max * 1e-4 的视为噪声,不参与白化(置单位矩阵) + _keep_mask = eigvals_n > eigvals_n.max() * 1e-4 + if _keep_mask.sum() < 2: + _keep_mask[:2] = True # 至少保留 2 个成分 + _kept_vals = np.where(_keep_mask, eigvals_n, 1.0) + inv_sqrt = np.where(_keep_mask, 1.0 / np.sqrt(np.maximum(_kept_vals, 1e-12)), 1.0) + Wn = eigvecs_n @ np.diag(inv_sqrt) @ eigvecs_n.T # 3) 均值 - self.mean_ = X.mean(axis=0, keepdims=True) # (1, p) + self.mean_ = X.mean(axis=0, keepdims=True) - # 4) 白化后的数据协方差 → PCA - X_w = (X - self.mean_) @ Wn # (n, p) - Cw = np.cov(X_w, rowvar=False) # (p, p) + # 4) 白化后 PCA + X_w = (X - self.mean_) @ Wn + Cw = np.cov(X_w, rowvar=False) eigvals_w, eigvecs_w = np.linalg.eigh(Cw) - # 降序排列(eigh 升序,翻转) - Wp = eigvecs_w[:, ::-1] # (p, p) + Wp = eigvecs_w[:, ::-1] # 5) 最终变换矩阵 - self.W_mnf_ = Wn @ Wp # (p, p) + self.W_mnf_ = Wn @ Wp return self def transform(self, X): X = self._to_ndarray(X) - return (X - self.mean_) @ self.W_mnf_[:, :self.n_components] + X = np.nan_to_num(X, nan=0.0, posinf=0.0, neginf=0.0) + result = (X - self.mean_) @ self.W_mnf_[:, :self.n_components] + # 防 SVR 拒绝 inf:clip 到 float32 安全范围 + result = np.nan_to_num(result, nan=0.0, posinf=0.0, neginf=0.0) + result = np.clip(result, -1e15, 1e15) + return result # ============================================================================