diff --git a/src/core/prediction/inference_batch.py b/src/core/prediction/inference_batch.py index 31b5022..e778178 100644 --- a/src/core/prediction/inference_batch.py +++ b/src/core/prediction/inference_batch.py @@ -433,6 +433,47 @@ class WaterQualityInference: return None + # ═══════════════════════════════════════════════════════════ + # DualStream_MNF 专用预处理:纯光谱重采样 → Pipeline 全自动 + # ═══════════════════════════════════════════════════════════ + + def _preprocess_dual_stream(self, spectra: pd.DataFrame, + metadata: dict) -> np.ndarray: + """纯光谱重采样到训练波长网格,返回后由 pipeline.predict() 全自动处理。 + + Pipeline 内置 FeatureUnion[PhysicalExtractor + MNFTransformer], + 会自动完成物理指数计算和 MNF 降维,无需外部补 WQI。 + """ + train_wl = metadata.get('train_wavelengths', None) + if train_wl is None or len(train_wl) == 0: + print("[DualStream_MNF] ⚠ 模型无 train_wavelengths,fallback 原样输入") + return spectra.values + + # 提取纯光谱列 + spec_cols = [] + for c in spectra.columns: + try: + float(str(c)); spec_cols.append(c) + except (ValueError, TypeError): + pass + + # np.interp 重采样:308/113/任意波段 → 模型训练波长 + spec_data = spectra[spec_cols].values.astype(np.float64) + src_wl = np.array([float(c) for c in spec_cols], dtype=np.float64) + dst_wl = np.array(train_wl, dtype=np.float64) + resampled = np.zeros((spec_data.shape[0], len(dst_wl)), dtype=np.float64) + for i in range(spec_data.shape[0]): + resampled[i] = np.interp(dst_wl, src_wl, spec_data[i], + left=np.nan, right=np.nan) + resampled = np.nan_to_num(resampled, nan=0.0) + + result = pd.DataFrame(resampled, + columns=[f'{wl:.6f}' for wl in train_wl]) + print(f"[DualStream_MNF] 纯光谱重采样: {len(spec_cols)} → {len(train_wl)} 列") + print(f"[DualStream_MNF] pipeline.predict() 将自动完成 Physical+MNF 变换") + print(f"[特征对齐] 最终输入维度: {result.shape}") + return result.values + def preprocess_spectra(self, spectra: pd.DataFrame) -> np.ndarray: """ 对光谱数据进行预处理 + 跨传感器光谱重采样。 @@ -477,34 +518,10 @@ class WaterQualityInference: metadata = self.loaded_model_data.get('metadata', {}) # ═══════════════════════════════════════════════════════════ - # ★ DualStream_MNF:纯光谱 → 重采样到训练波长 → pipeline.predict() - # Pipeline 内置的 FeatureUnion[PhysicalExtractor + MNF] - # 自动计算物理指数和降维,无需外部补 WQI + # ★ DualStream_MNF:纯光谱重采样 → pipeline.predict() 全自动 # ═══════════════════════════════════════════════════════════ if actual_preprocess_method == "DualStream_MNF" and isinstance(model, Pipeline): - print("[DualStream_MNF] 推理:纯光谱重采样 → Pipeline 全自动处理") - train_wl = metadata.get('train_wavelengths', None) - if train_wl is not None and len(train_wl) > 0: - spec_cols = [] - for c in spectra.columns: - try: - float(str(c)); spec_cols.append(c) - except (ValueError, TypeError): - pass - spec_data = spectra[spec_cols].values.astype(np.float64) - src_wl = np.array([float(c) for c in spec_cols], dtype=np.float64) - dst_wl = np.array(train_wl, dtype=np.float64) - resampled = np.zeros((spec_data.shape[0], len(dst_wl)), dtype=np.float64) - for i in range(spec_data.shape[0]): - resampled[i] = np.interp(dst_wl, src_wl, spec_data[i], - left=np.nan, right=np.nan) - resampled = np.nan_to_num(resampled, nan=0.0) - spectra = pd.DataFrame(resampled, - columns=[f'{wl:.6f}' for wl in train_wl]) - print(f"[DualStream_MNF] 纯光谱重采样完成: {spectra.shape[1]} 列 " - f"→ pipeline.predict() 将自动完成 Physical+MNF 变换") - print(f"[特征对齐] 最终输入维度: {spectra.shape}") - return spectra.values + return self._preprocess_dual_stream(spectra, metadata) train_wavelengths = metadata.get('train_wavelengths', None) # 旧模型无 train_wavelengths → 不做波长匹配,走下方分支 B 的 linspace 路径