From ee6ccd3f8f5c82936e8edb274482c478a5805155 Mon Sep 17 00:00:00 2001
From: "2569718930@qq.com" <2569718930@qq.com>
Date: Sun, 1 Mar 2026 15:59:10 +0800
Subject: [PATCH] feat: add /deb command for DEB accuracy report with per-day
breakdown and model MAE comparison
---
bot_listener.py | 111 ++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 102 insertions(+), 9 deletions(-)
diff --git a/bot_listener.py b/bot_listener.py
index e8dbe8bc..f8e29b93 100644
--- a/bot_listener.py
+++ b/bot_listener.py
@@ -78,15 +78,7 @@ 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:
- # 展示准确率(如果有历史数据)
- 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 📈 DEB 历史战绩:{details_str}"
-
- insights.insert(0, f"🧬 DEB 融合预测:{blended_high}{temp_symbol} ({weight_info}){acc_tag}")
+ insights.insert(0, f"🧬 DEB 融合预测:{blended_high}{temp_symbol} ({weight_info})")
ai_features.append(f"🧬 DEB系统已通过历史偏差矫正算出期待点是: {blended_high}{temp_symbol}。")
# 顺便把今天的预测记录下来供之后回测用
@@ -322,6 +314,7 @@ def start_bot():
"🌡️ PolyWeather 天气查询机器人\n\n"
"可用指令:\n"
"/city [城市名] - 查询城市天气预测与实测\n"
+ "/deb [城市名] - 查看 DEB 融合预测准确率\n"
"/id - 获取当前聊天的 Chat ID\n\n"
"示例: /city 伦敦"
)
@@ -335,6 +328,106 @@ def start_bot():
parse_mode="HTML",
)
+ @bot.message_handler(commands=["deb"])
+ def deb_accuracy(message):
+ """查询 DEB 融合预测的历史准确率"""
+ try:
+ parts = message.text.split(maxsplit=1)
+ if len(parts) < 2:
+ bot.reply_to(message, "❓ 用法: /deb ankara", parse_mode="HTML")
+ return
+
+ city_input = parts[1].strip().lower()
+ # 复用城市名映射
+ city_aliases = {
+ "ank": "ankara", "lon": "london", "par": "paris",
+ "nyc": "new york", "chi": "chicago", "dal": "dallas",
+ "mia": "miami", "atl": "atlanta", "sea": "seattle",
+ "tor": "toronto", "sel": "seoul", "ba": "buenos aires",
+ "wel": "wellington",
+ }
+ city_name = city_aliases.get(city_input, city_input)
+
+ from src.analysis.deb_algorithm import get_deb_accuracy, load_history
+ import os as _os
+
+ # 获取详细历史数据
+ project_root = _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 or not data[city_name]:
+ bot.reply_to(message, f"❌ 暂无 {city_name} 的历史数据", parse_mode="HTML")
+ return
+
+ city_data = data[city_name]
+ from datetime import datetime as _dt
+ today_str = _dt.now().strftime("%Y-%m-%d")
+
+ lines = [f"📊 DEB 准确率报告 - {city_name.title()}\n"]
+
+ # 逐日明细
+ lines.append("📅 逐日记录:")
+ total_days = 0
+ hits = 0
+ deb_errors = []
+ model_errors = {}
+
+ for date_str in sorted(city_data.keys()):
+ record = city_data[date_str]
+ actual = record.get('actual_high')
+ deb_pred = record.get('deb_prediction')
+ forecasts = record.get('forecasts', {})
+
+ if actual is None:
+ continue
+
+ actual_wu = round(actual)
+
+ # DEB 命中判断
+ if deb_pred is not None and date_str != today_str:
+ total_days += 1
+ deb_wu = round(deb_pred)
+ hit = deb_wu == actual_wu
+ if hit: hits += 1
+ deb_errors.append(abs(deb_pred - actual))
+ icon = "✅" if hit else "❌"
+ lines.append(f" {date_str}: DEB {deb_pred}→{deb_wu} vs 实测 {actual}→{actual_wu} {icon}")
+ elif date_str == today_str:
+ lines.append(f" {date_str}: 📍 今天进行中 (实测暂 {actual})")
+ else:
+ lines.append(f" {date_str}: 实测 {actual}→{actual_wu} (无DEB记录)")
+
+ # 各模型误差统计
+ if date_str != today_str and actual is not None:
+ for model, pred in forecasts.items():
+ if pred is not None:
+ if model not in model_errors:
+ model_errors[model] = []
+ model_errors[model].append(abs(pred - actual))
+
+ # 汇总
+ if total_days > 0:
+ hit_rate = hits / total_days * 100
+ deb_mae = sum(deb_errors) / len(deb_errors)
+ lines.append(f"\n🎯 DEB 总战绩:WU命中 {hits}/{total_days} ({hit_rate:.0f}%) | MAE: {deb_mae:.1f}°")
+
+ # 和各模型 MAE 对比
+ if model_errors:
+ lines.append(f"\n📈 模型 MAE 对比:")
+ model_maes = {m: sum(e)/len(e) for m, e in model_errors.items() if e}
+ sorted_models = sorted(model_maes.items(), key=lambda x: x[1])
+ for m, mae in sorted_models:
+ tag = " ⭐" if mae <= deb_mae else ""
+ lines.append(f" {m}: {mae:.1f}°{tag}")
+ lines.append(f" DEB融合: {deb_mae:.1f}°")
+ else:
+ lines.append("\n⏳ 尚无完整的 DEB 预测记录,明天起开始统计。")
+
+ bot.reply_to(message, "\n".join(lines), parse_mode="HTML")
+ except Exception as e:
+ bot.reply_to(message, f"❌ 查询失败: {e}")
+
@bot.message_handler(commands=["city"])
def get_city_info(message):
"""查询指定城市的天气详情"""