refactor: 抽取 _preprocess_dual_stream 独立方法

- preprocess_spectra 中 DualStream_MNF 分支从 25 行内联代码
  变为 1 行方法调用: self._preprocess_dual_stream(spectra, metadata)
- 新方法含完整文档、fallback 路径、重采样逻辑
- 与旧 WQI 补齐/linspace 路径完全解耦
This commit is contained in:
duxin
2026-07-29 13:23:13 +08:00
parent f4a927386b
commit f3150f7807

View File

@ -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_wavelengthsfallback 原样输入")
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 路径