From f4a927386bbd1f62774d5924f66a687ffbf1f6c4 Mon Sep 17 00:00:00 2001 From: duxin Date: Wed, 29 Jul 2026 13:15:10 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20DualStream=20=E7=BA=AF=E5=85=89?= =?UTF-8?q?=E8=B0=B1=E8=BE=93=E5=85=A5=20=E2=80=94=20=E6=B6=88=E9=99=A4=20?= =?UTF-8?q?WQI=20=E5=86=97=E4=BD=99=E5=8F=8C=E5=90=91=E6=96=AD=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 训练端: - DualStream_MNF 时只取纯光谱列(50列)传给 Pipeline - PhysicalFeatureExtractor + MNFTransformer 都只收纯光谱 - 不再从 CSV 预读 WQI 列混入输入 推理端: - 只做 308→50 光谱重采样,不补 WQI - pipeline.predict() 自动完成 Physical 指数计算 + MNF 降维 - 删除 30+ 行 WQI 补齐代码 训练/推理完全对称: 纯光谱入 → FeatureUnion → SVR 出 --- src/core/modeling/modeling_batch.py | 11 ++++++++- src/core/prediction/inference_batch.py | 34 +++++++------------------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/core/modeling/modeling_batch.py b/src/core/modeling/modeling_batch.py index 497a3e2..c0add04 100644 --- a/src/core/modeling/modeling_batch.py +++ b/src/core/modeling/modeling_batch.py @@ -606,7 +606,16 @@ class WaterQualityModelingBatch: print(f"开始训练模型: {model_name} (预处理: {preprocess_method})") - # 使用指定方法分割训练集和测试集(用原始 X_raw,Pipeline 内置 transform 处理) + # ═══════════════════════════════════════════════════════════ + # ★ DualStream_MNF:只取纯光谱列,WQI 由 Pipeline 内 PhysicalExtractor 动态计算 + # ═══════════════════════════════════════════════════════════ + if preprocess_method == "DualStream_MNF": + _spec_cols = [c for c in X_raw.columns if self._is_wavelength_column(c)] + X_raw = X_raw[_spec_cols] + print(f"[DualStream_MNF] 精简为纯光谱: {X_raw.shape[1]} 列 " + f"({X_raw.columns[0]} ~ {X_raw.columns[-1]} nm)") + + # 使用指定方法分割训练集和测试集 X_train, X_test, y_train, y_test = self.split_data( X_raw, y, method=split_method, test_size=test_size, random_state=random_state ) diff --git a/src/core/prediction/inference_batch.py b/src/core/prediction/inference_batch.py index aed83b1..31b5022 100644 --- a/src/core/prediction/inference_batch.py +++ b/src/core/prediction/inference_batch.py @@ -477,15 +477,14 @@ class WaterQualityInference: metadata = self.loaded_model_data.get('metadata', {}) # ═══════════════════════════════════════════════════════════ - # ★ DualStream_MNF:重建训练特征空间(308→113列), - # 让 Pipeline.predict() 完整走 imputer→preproc→cleaner→SVR + # ★ DualStream_MNF:纯光谱 → 重采样到训练波长 → pipeline.predict() + # Pipeline 内置的 FeatureUnion[PhysicalExtractor + MNF] + # 自动计算物理指数和降维,无需外部补 WQI # ═══════════════════════════════════════════════════════════ if actual_preprocess_method == "DualStream_MNF" and isinstance(model, Pipeline): - print("[DualStream_MNF] 推理:重建训练特征集,交给 Pipeline 完整处理") + print("[DualStream_MNF] 推理:纯光谱重采样 → Pipeline 全自动处理") 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: - # 1) 重采样 308 → 训练波长 + if train_wl is not None and len(train_wl) > 0: spec_cols = [] for c in spectra.columns: try: @@ -500,26 +499,11 @@ class WaterQualityInference: 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) - wl_col_names = [f'{wl:.6f}' for wl in train_wl] - spectra = pd.DataFrame(resampled, columns=wl_col_names) - # 2) 计算 WQI + 补零到训练列数 - n_need = len(train_cols) - if spectra.shape[1] < n_need: - print(f"[DualStream_MNF] 计算 WQI: {spectra.shape[1]} → {n_need}") - try: - from src.utils.water_index import WaterQualityIndexCalculator - wqi = WaterQualityIndexCalculator().calculate_many( - WaterQualityIndexCalculator().list_available(), - spectra, fast=True) - spectra = pd.concat([spectra, wqi], axis=1) - except Exception as e: - print(f"[DualStream_MNF] WQI 失败: {e}") - while spectra.shape[1] < n_need: - spectra[f'_pad_{spectra.shape[1]}'] = 0.0 - spectra = spectra.iloc[:, :n_need] - print(f"[DualStream_MNF] 特征重建完成: {spectra.shape}") + 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}") - # 返回 DataFrame,后续 model.predict() 走完整 Pipeline return spectra.values train_wavelengths = metadata.get('train_wavelengths', None)