feat: 新增 Physical_Only 预处理分支 — 纯物理特征+标准化,与 MNF A/B 对比

spectral_Preprocessing.py:
- 新增 Physical_Only 分支: Pipeline[PhysicalFeatureExtractor + StandardScaler]
- 纯物理特征流: 20个指数 → StandardScaler → SVR
- DualStream_MNF 逻辑完全不变

modeling_batch.py:
- preprocessing_methods 新增 Physical_Only
- 训练时 Physical_Only 也只取纯光谱50列
- 波长列表传递覆盖 Physical_Only

GUI:
- 两个面板同步新增「纯物理特征 (指数+标准化)」选项
This commit is contained in:
duxin
2026-07-29 14:32:59 +08:00
parent f3150f7807
commit 6849ff6877
4 changed files with 16 additions and 8 deletions

View File

@ -241,7 +241,7 @@ class WaterQualityModelingBatch:
# 预处理方法列表
self.preprocessing_methods = [
"None", "MMS", "SS", "CT", "SNV", "MA", "SG", "MSC", "D1", "D2", "DT", "WVAE",
"DualStream_MNF"
"DualStream_MNF", "Physical_Only"
]
# 样本划分方法列表
@ -609,10 +609,10 @@ class WaterQualityModelingBatch:
# ═══════════════════════════════════════════════════════════
# ★ DualStream_MNF只取纯光谱列WQI 由 Pipeline 内 PhysicalExtractor 动态计算
# ═══════════════════════════════════════════════════════════
if preprocess_method == "DualStream_MNF":
if preprocess_method in ("DualStream_MNF", "Physical_Only"):
_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]}"
print(f"[{preprocess_method}] 精简为纯光谱: {X_raw.shape[1]}"
f"({X_raw.columns[0]} ~ {X_raw.columns[-1]} nm)")
# 使用指定方法分割训练集和测试集
@ -637,9 +637,9 @@ class WaterQualityModelingBatch:
base_model.set_params(verbose=-1)
# ============ 关键:把预处理器塞进 Pipeline ============
# DualStream_MNF 需要传入波长列表,供 PhysicalFeatureExtractor 定位波段
# DualStream_MNF / Physical_Only 需要波长列表,供 PhysicalFeatureExtractor 定位波段
_wl_list = None
if preprocess_method == "DualStream_MNF":
if preprocess_method in ("DualStream_MNF", "Physical_Only"):
_wl_list = self._extract_train_wavelengths(X_raw.columns)
preproc = get_preprocessing_transformer(preprocess_method, wavelengths=_wl_list)
pipeline = Pipeline([

View File

@ -41,6 +41,7 @@ PREPROC_CHINESE = {
'CT': '中心化 (CT)',
'WVAE': '小波去噪 (WVAE)',
'DualStream_MNF': '双流MNF (物理指数+降维)',
'Physical_Only': '纯物理特征 (指数+标准化)',
}
# 模型类型:内部键 -> 显示文本
@ -177,7 +178,7 @@ class Step8MlTrainPanel(QWidget):
preproc_grid = QGridLayout()
self.preproc_checkboxes = {}
preproc_methods = ['None', 'MMS', 'SS', 'SNV', 'MA', 'SG', 'MSC', 'D1', 'D2', 'DT', 'CT', 'WVAE', 'DualStream_MNF']
preproc_methods = ['None', 'MMS', 'SS', 'SNV', 'MA', 'SG', 'MSC', 'D1', 'D2', 'DT', 'CT', 'WVAE', 'DualStream_MNF', 'Physical_Only']
for i, method in enumerate(preproc_methods):
checkbox = QCheckBox(PREPROC_CHINESE.get(method, method))

View File

@ -43,6 +43,7 @@ PREPROC_CHINESE = {
"CT": "中心化 (CT)",
"WVAE": "小波去噪 (WVAE)",
"DualStream_MNF": "双流MNF (物理指数+降维)",
"Physical_Only": "纯物理特征 (指数+标准化)",
}
MODEL_CHINESE = {
@ -70,7 +71,7 @@ SPLIT_CHINESE = {
"random": "随机划分 (Random)",
}
PREPROC_METHODS = ["None", "MMS", "SS", "SNV", "MA", "SG", "MSC", "D1", "D2", "DT", "CT", "WVAE", "DualStream_MNF"]
PREPROC_METHODS = ["None", "MMS", "SS", "SNV", "MA", "SG", "MSC", "D1", "D2", "DT", "CT", "WVAE", "DualStream_MNF", "Physical_Only"]
MODEL_GROUPS = [
("【线性模型】", ["LinearRegression", "Ridge", "Lasso", "ElasticNet", "PLS"]),
("【树模型】", ["DecisionTree", "RF", "ExtraTrees", "XGBoost", "LightGBM", "CatBoost"]),

View File

@ -553,7 +553,13 @@ def get_preprocessing_transformer(method: str, wavelengths=None):
from sklearn.pipeline import FeatureUnion
return FeatureUnion([
('physical', PhysicalFeatureExtractor(wavelengths=wavelengths)),
('mnf', MNFTransformer()), # n_components=0.95 自动确定
('mnf', MNFTransformer()),
])
if method == "Physical_Only":
from sklearn.pipeline import Pipeline as _Pipeline
return _Pipeline([
("physical", PhysicalFeatureExtractor(wavelengths=wavelengths)),
("scaler", StandardScaler()),
])
if method not in _PREPROCESSING_TRANSFORMERS:
print(f"未知预处理方法 '{method}',回退为 IdentityTransformer")