diff --git a/src/core/modeling/modeling_batch.py b/src/core/modeling/modeling_batch.py index fc1d917..10e4cc9 100644 --- a/src/core/modeling/modeling_batch.py +++ b/src/core/modeling/modeling_batch.py @@ -250,6 +250,9 @@ class WaterQualityModelingBatch: self.results = {} self.best_models = {} + # ★ 黄金光谱区间:统一收缩到 400-1000nm,消除边缘噪声和跨传感器不一致 + WAVELENGTH_RANGE = (400.0, 1000.0) + @staticmethod def _is_wavelength_column(col_name: str) -> bool: """判断列名是否为波长值(纯数字字符串,如 '374.285004')""" @@ -259,22 +262,35 @@ class WaterQualityModelingBatch: except (ValueError, TypeError): return False + @classmethod + def _is_wavelength_in_range(cls, col_name: str) -> bool: + """判断列名是否为波长值且在黄金区间 [400, 1000] nm 内。""" + try: + wl = float(str(col_name)) + lo, hi = cls.WAVELENGTH_RANGE + return lo <= wl <= hi + except (ValueError, TypeError): + return False + @staticmethod def _is_wqi_column(col_name: str) -> bool: """判断列名是否为 WQI 水质指数列('WQI_' 前缀)""" return str(col_name).startswith('WQI_') - @staticmethod - def _extract_train_wavelengths(columns) -> List[float]: - """从列名列表中提取波长值(float 列表) + @classmethod + def _extract_train_wavelengths(cls, columns) -> List[float]: + """从列名列表中提取波长值(float 列表),自动过滤到黄金区间。 - 遍历列名,将所有可转为 float 的列名提取为波长列表。 + 遍历列名,将所有可转为 float 且落在 [400, 1000] nm 的列名提取为波长列表。 用于写入模型 metadata['train_wavelengths'],供推理端光谱重采样。 """ + lo, hi = cls.WAVELENGTH_RANGE wl_list = [] for c in columns: try: - wl_list.append(float(str(c))) + wl = float(str(c)) + if lo <= wl <= hi: + wl_list.append(wl) except (ValueError, TypeError): pass return wl_list @@ -327,8 +343,8 @@ class WaterQualityModelingBatch: # 跳过元数据列 if col_lower in _meta_patterns: continue - # 保留波长列 - if self._is_wavelength_column(col): + # 保留波长列(仅黄金区间 400-1000nm) + if self._is_wavelength_in_range(col): feature_indices.append(i) # 保留 WQI 列 elif self._is_wqi_column(col): @@ -613,9 +629,9 @@ class WaterQualityModelingBatch: # ★ DualStream_MNF:只取纯光谱列,WQI 由 Pipeline 内 PhysicalExtractor 动态计算 # ═══════════════════════════════════════════════════════════ if preprocess_method in ("DualStream_MNF", "Physical_Only"): - _spec_cols = [c for c in X_raw.columns if self._is_wavelength_column(c)] + _spec_cols = [c for c in X_raw.columns if self._is_wavelength_in_range(c)] X_raw = X_raw[_spec_cols] - print(f"[{preprocess_method}] 精简为纯光谱: {X_raw.shape[1]} 列 " + print(f"[{preprocess_method}] 精简为纯光谱(400-1000nm): {X_raw.shape[1]} 列 " f"({X_raw.columns[0]} ~ {X_raw.columns[-1]} nm)") # 使用指定方法分割训练集和测试集 @@ -975,9 +991,9 @@ class WaterQualityModelingBatch: X_clean = X_raw[mask] - # 只保留纯光谱列(与 DualStream_MNF Pipeline 内的逻辑一致) + # 只保留纯光谱列(与 DualStream_MNF Pipeline 内的逻辑一致,400-1000nm) _spec_cols = [c for c in X_clean.columns - if self._is_wavelength_column(c)] + if self._is_wavelength_in_range(c)] X_spec = X_clean[_spec_cols].values.astype(np.float64) try: