From c9374a489bd23319dfd2fa85b62ee56b6f812611 Mon Sep 17 00:00:00 2001 From: duxin Date: Wed, 29 Jul 2026 10:53:58 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20DualStream=5FMNF=20=E6=8E=A8=E7=90=86?= =?UTF-8?q?=E5=85=88=E9=87=8D=E9=87=87=E6=A0=B7308=E2=86=92=E8=AE=AD?= =?UTF-8?q?=E7=BB=83=E7=BD=91=E6=A0=BC=E5=86=8D=E8=BF=9BPipeline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 推理数据 308 波段 vs 训练时 113 列(50光谱+63WQI)维度不同 - SimpleImputer fit在113列上不接受308列输入 - 修复: 先 np.interp 重采样到训练波长网格, 再 WQI 补齐, 然后喂入 Pipeline 的 imputer+preproc+cleaner 最终进 SVR --- src/core/prediction/inference_batch.py | 51 +++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/core/prediction/inference_batch.py b/src/core/prediction/inference_batch.py index 4767d22..cce01b2 100644 --- a/src/core/prediction/inference_batch.py +++ b/src/core/prediction/inference_batch.py @@ -478,13 +478,54 @@ class WaterQualityInference: # ═══════════════════════════════════════════════════════════ # ★ DualStream_MNF 快速通道:Pipeline 已内置 MNF + 物理指数 - # 无需手动重采样或 WQI 补齐,直接走 Pipeline 的 preproc 步骤 + # 但需先将推理光谱重采样到训练特征空间(308→113列), + # 再走 Pipeline 的 imputer+preproc 步骤 # ═══════════════════════════════════════════════════════════ if actual_preprocess_method == "DualStream_MNF" and isinstance(model, Pipeline): - print("[DualStream_MNF] 推理直通 Pipeline(MNF+物理指数已内置)") - # Pipeline 的 imputer + preproc 步骤会处理一切 - spectra_processed = model.named_steps['imputer'].transform(spectra.values) - spectra_processed = model.named_steps['preproc'].transform(spectra_processed) + print("[DualStream_MNF] 推理:先重建训练特征集再直通 Pipeline") + # 1) 重采样 308 波段 → 训练波长网格 + train_wl = metadata.get('train_wavelengths', None) + train_cols = metadata.get('train_columns', None) + if train_wl is not None and len(train_wl) > 0 and train_cols is not None: + # 从 spectra 中提取光谱列(列名可转 float 的即为波长列) + 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) + # 2) 计算 WQI 补齐到训练列数 + wl_col_names = [f'{wl:.6f}' for wl in train_wl] + spectra_df = pd.DataFrame(resampled, columns=wl_col_names) + n_need = len(train_cols) + if spectra_df.shape[1] < n_need: + print(f"[DualStream_MNF] 计算 WQI 补齐: {spectra_df.shape[1]} → {n_need}") + try: + from src.utils.water_index import WaterQualityIndexCalculator + calc = WaterQualityIndexCalculator() + formulas = calc.list_available() + wqi = calc.calculate_many(formulas, spectra_df, fast=True) + spectra_df = pd.concat([spectra_df, wqi], axis=1) + except Exception as e: + print(f"[DualStream_MNF] WQI 失败: {e}") + # 如果还不够,补零 + while spectra_df.shape[1] < n_need: + spectra_df[f'_pad_{spectra_df.shape[1]}'] = 0.0 + spectra_df = spectra_df.iloc[:, :n_need] + # 3) 喂入 Pipeline + spectra_processed = model.named_steps['imputer'].transform(spectra_df.values) + spectra_processed = model.named_steps['preproc'].transform(spectra_processed) + else: + spectra_processed = model.named_steps['imputer'].transform(spectra.values) + spectra_processed = model.named_steps['preproc'].transform(spectra_processed) spectra_processed = np.nan_to_num(spectra_processed, nan=0.0, posinf=0.0, neginf=0.0) print(f"[DualStream_MNF] 预处理完成: {spectra_processed.shape}") print(f"[特征对齐] 最终输入维度: {spectra_processed.shape}")