feat: 预测结果百分位裁剪 — 消除极端异常值拉爆专题图色阶
- 新增 _clip_outliers(P1-P99) 方法,预测完成后自动裁剪 - 水体边界零值区域导致模型外推极端值(-86~7026), 裁剪后克里金插值色阶不再被拉爆,正常空间细节可见 - 无异常值时不触发裁剪(零开销)
This commit is contained in:
@ -740,12 +740,52 @@ class WaterQualityInference:
|
|||||||
print(f"预测值范围: [{np.min(predictions):.4f}, {np.max(predictions):.4f}]")
|
print(f"预测值范围: [{np.min(predictions):.4f}, {np.max(predictions):.4f}]")
|
||||||
print(f"预测值统计: 均值={np.mean(predictions):.4f}, 标准差={np.std(predictions):.4f}")
|
print(f"预测值统计: 均值={np.mean(predictions):.4f}, 标准差={np.std(predictions):.4f}")
|
||||||
|
|
||||||
|
# ★ 百分位裁剪:去除极端异常值,避免专题图色阶被拉爆
|
||||||
|
predictions = self._clip_outliers(predictions)
|
||||||
|
|
||||||
return predictions
|
return predictions
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"预测失败: {e}")
|
print(f"预测失败: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _clip_outliers(predictions: np.ndarray, lower_pct: float = 1.0,
|
||||||
|
upper_pct: float = 99.0) -> np.ndarray:
|
||||||
|
"""百分位裁剪:将极端异常值裁剪到合理范围。
|
||||||
|
|
||||||
|
水体边界/零值区域的光谱异常会导致模型外推到极端值
|
||||||
|
(如 BGA 预测 -86 ~ 7026),若不处理,专题图的克里金
|
||||||
|
插值色阶会被拉爆,正常空间变化完全不可见。
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
predictions : np.ndarray
|
||||||
|
原始预测值
|
||||||
|
lower_pct : float
|
||||||
|
下百分位(默认 1%,低于此分位数的值被裁剪)
|
||||||
|
upper_pct : float
|
||||||
|
上百分位(默认 99%,高于此分位数的值被裁剪)
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
np.ndarray
|
||||||
|
裁剪后的预测值(副本)
|
||||||
|
"""
|
||||||
|
lo = np.percentile(predictions, lower_pct)
|
||||||
|
hi = np.percentile(predictions, upper_pct)
|
||||||
|
# 只在实际有异常值时才裁剪
|
||||||
|
if lo >= hi:
|
||||||
|
return predictions
|
||||||
|
n_clipped_lo = int(np.sum(predictions < lo))
|
||||||
|
n_clipped_hi = int(np.sum(predictions > hi))
|
||||||
|
if n_clipped_lo == 0 and n_clipped_hi == 0:
|
||||||
|
return predictions
|
||||||
|
print(f"[异常值裁剪] P{lower_pct:.0f}={lo:.4f}, P{upper_pct:.0f}={hi:.4f}, "
|
||||||
|
f"裁剪低端 {n_clipped_lo} 个, 高端 {n_clipped_hi} 个 "
|
||||||
|
f"({(n_clipped_lo + n_clipped_hi) / len(predictions) * 100:.1f}%)")
|
||||||
|
return np.clip(predictions, lo, hi)
|
||||||
|
|
||||||
def save_predictions(self, coords: pd.DataFrame, predictions: np.ndarray,
|
def save_predictions(self, coords: pd.DataFrame, predictions: np.ndarray,
|
||||||
output_path: str, prediction_column: str = 'prediction',
|
output_path: str, prediction_column: str = 'prediction',
|
||||||
wqi_columns: Optional[pd.DataFrame] = None):
|
wqi_columns: Optional[pd.DataFrame] = None):
|
||||||
|
|||||||
Reference in New Issue
Block a user