From e3a08e0ad0a26aaafbe902c7e8ce927b4cd665ee Mon Sep 17 00:00:00 2001 From: duxin Date: Thu, 30 Jul 2026 13:12:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8E=A8=E7=90=86=E7=AB=AF=E5=85=89?= =?UTF-8?q?=E8=B0=B1=E8=A6=86=E7=9B=96=E7=8E=87=E6=99=BA=E8=83=BD=E9=A2=84?= =?UTF-8?q?=E8=AD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 _check_spectral_coverage() 静态方法 - 比较预测波长 vs 训练波长的起止范围 - 左端缺口 >15nm → 黄色警告:蓝端/紫外特征丢失 - 右端缺口 >15nm → 黄色警告:近红外特征丢失 - 在 _preprocess_dual_stream 和 preprocess_spectra 两处调用 - 使用 ANSI \033[93m 黄色高亮,不中断程序运行 --- src/core/prediction/inference_batch.py | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/core/prediction/inference_batch.py b/src/core/prediction/inference_batch.py index fbf24ea..2061429 100644 --- a/src/core/prediction/inference_batch.py +++ b/src/core/prediction/inference_batch.py @@ -443,6 +443,28 @@ class WaterQualityInference: # DualStream_MNF 专用预处理:纯光谱重采样 → Pipeline 全自动 # ═══════════════════════════════════════════════════════════ + @staticmethod + def _check_spectral_coverage(train_wl, infer_wl): + """光谱覆盖率智能预警:检测预测数据波长范围是否充分覆盖训练波长。 + + 若预测波长的起止端与训练波长差距超过 15nm,说明边缘波段缺失, + np.interp 会依赖 left/right 恒定外推补齐,可能导致特征丢失。 + """ + train_min, train_max = np.min(train_wl), np.max(train_wl) + infer_min, infer_max = np.min(infer_wl), np.max(infer_wl) + + gap_left = infer_min - train_min + gap_right = train_max - infer_max + + if gap_left > 15: + print(f"\033[93m[WARN] 预测数据起始波长 ({infer_min:.1f}nm) 晚于" + f" 训练波长 ({train_min:.1f}nm) 达 {gap_left:.0f}nm!" + f"系统将自动向左横推补齐,这可能会导致蓝端/紫外特征丢失。\033[0m") + if gap_right > 15: + print(f"\033[93m[WARN] 预测数据截止波长 ({infer_max:.1f}nm) 短于" + f" 训练波长 ({train_max:.1f}nm) 达 {gap_right:.0f}nm!" + f"系统将自动向右横推补齐,这可能会导致近红外特征丢失,影响预测精度。\033[0m") + def _preprocess_dual_stream(self, spectra: pd.DataFrame, metadata: dict) -> np.ndarray: """纯光谱重采样到训练波长网格,返回后由 pipeline.predict() 全自动处理。 @@ -471,6 +493,9 @@ class WaterQualityInference: 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) + + # ★ 光谱覆盖率预警 + self._check_spectral_coverage(train_wl, src_wl) resampled = np.zeros((spec_data.shape[0], len(dst_wl)), dtype=np.float64) for i in range(spec_data.shape[0]): y_vals = spec_data[i] @@ -574,6 +599,9 @@ class WaterQualityInference: train_wl_arr = np.array(train_wavelengths, dtype=np.float64) target_wl_arr = np.array(target_wavelengths, dtype=np.float64) + # ★ 光谱覆盖率预警 + self._check_spectral_coverage(train_wavelengths, target_wavelengths) + print(f"[光谱重采样] 执行重采样: {len(target_wavelengths)} → " f"{len(train_wavelengths)} 个波长点 ...") resampled = np.zeros((spectral_data.shape[0], len(train_wavelengths)),