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.mean(predictions):.4f}, 标准差={np.std(predictions):.4f}")
|
||||
|
||||
# ★ 百分位裁剪:去除极端异常值,避免专题图色阶被拉爆
|
||||
predictions = self._clip_outliers(predictions)
|
||||
|
||||
return predictions
|
||||
|
||||
except Exception as e:
|
||||
print(f"预测失败: {e}")
|
||||
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,
|
||||
output_path: str, prediction_column: str = 'prediction',
|
||||
wqi_columns: Optional[pd.DataFrame] = None):
|
||||
|
||||
Reference in New Issue
Block a user