feat: DEB accuracy tracking - save predictions, compute WU hit rate and MAE

This commit is contained in:
2569718930@qq.com
2026-03-01 15:53:29 +08:00
parent 9baf426b38
commit ee535e9efa
2 changed files with 65 additions and 5 deletions
+10 -2
View File
@@ -78,12 +78,20 @@ def analyze_weather_trend(weather_data, temp_symbol, city_name=None):
if city_name and current_forecasts:
blended_high, weight_info = calculate_dynamic_weights(city_name, current_forecasts)
if blended_high is not None:
insights.insert(0, f"🧬 <b>DEB 融合预测</b><b>{blended_high}{temp_symbol}</b> ({weight_info})")
# 展示准确率(如果有历史数据)
from src.analysis.deb_algorithm import get_deb_accuracy
accuracy = get_deb_accuracy(city_name)
acc_tag = ""
if accuracy:
hit_rate, mae, total_days, details_str = accuracy
acc_tag = f"\n 📈 <b>DEB 历史战绩</b>{details_str}"
insights.insert(0, f"🧬 <b>DEB 融合预测</b><b>{blended_high}{temp_symbol}</b> ({weight_info}){acc_tag}")
ai_features.append(f"🧬 DEB系统已通过历史偏差矫正算出期待点是: {blended_high}{temp_symbol}")
# 顺便把今天的预测记录下来供之后回测用
try:
update_daily_record(city_name, local_date_str, current_forecasts, max_so_far)
update_daily_record(city_name, local_date_str, current_forecasts, max_so_far, deb_prediction=blended_high)
except:
pass
+55 -3
View File
@@ -45,11 +45,12 @@ def save_history(filepath, data):
except Exception as e:
print(f"Error saving history: {e}")
def update_daily_record(city_name, date_str, forecasts, actual_high):
def update_daily_record(city_name, date_str, forecasts, actual_high, deb_prediction=None):
"""
保存/更新某城市某天的各个模型预报与最终实测值
forecasts: dict, 例如 {"ECMWF": 28.5, "GFS": 30.0, ...}
actual_high: float, 最终实测最高温
deb_prediction: float, DEB 融合预测值(用于准确率追踪)
"""
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
history_file = os.path.join(project_root, 'data', 'daily_records.json')
@@ -61,14 +62,15 @@ def update_daily_record(city_name, date_str, forecasts, actual_high):
if date_str not in data[city_name]:
data[city_name][date_str] = {}
# 避免无意义的频繁磁盘写入:如果数据没有变化,直接返回
# 避免无意义的频繁磁盘写入
old_actual = data[city_name][date_str].get('actual_high')
if old_actual == actual_high and data[city_name][date_str].get('forecasts') == forecasts:
return
data[city_name][date_str]['forecasts'] = forecasts
# 只要仍在更新或者已经结束,都记录最新高点
data[city_name][date_str]['actual_high'] = actual_high
if deb_prediction is not None:
data[city_name][date_str]['deb_prediction'] = deb_prediction
# 自动清理:只保留最近 14 天的记录(DEB 只用 7 天,14 天留足余量)
cutoff = (datetime.now() - timedelta(days=14)).strftime("%Y-%m-%d")
@@ -162,3 +164,53 @@ def calculate_dynamic_weights(city_name, current_forecasts, lookback_days=7):
return round(blended_high, 1), " | ".join(weight_str_parts)
def get_deb_accuracy(city_name):
"""
计算 DEB 融合预测的历史准确率
返回: (hit_rate, mae, total_days, details_str) 或 None
- hit_rate: WU 结算命中率 (DEB 四舍五入 == 实测四舍五入)
- mae: 平均绝对误差
- total_days: 有效天数
- details_str: 格式化的展示字符串
"""
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
history_file = os.path.join(project_root, 'data', 'daily_records.json')
data = load_history(history_file)
if city_name not in data:
return None
city_data = data[city_name]
today_str = datetime.now().strftime("%Y-%m-%d")
hits = 0
total = 0
errors = []
for date_str in sorted(city_data.keys()):
if date_str == today_str:
continue # 跳过今天,还没结算
record = city_data[date_str]
deb_pred = record.get('deb_prediction')
actual = record.get('actual_high')
if deb_pred is None or actual is None:
continue
total += 1
deb_wu = round(deb_pred)
actual_wu = round(actual)
if deb_wu == actual_wu:
hits += 1
errors.append(abs(deb_pred - actual))
if total == 0:
return None
hit_rate = hits / total * 100
mae = sum(errors) / len(errors)
details_str = f"过去{total}天 WU命中 {hits}/{total} ({hit_rate:.0f}%) | MAE: {mae:.1f}°"
return hit_rate, mae, total, details_str