feat: replace AI-computed probability with math-based normal distribution from ensemble data
This commit is contained in:
@@ -174,6 +174,43 @@ def analyze_weather_trend(weather_data, temp_symbol, city_name=None):
|
|||||||
msg2 = f"⚡ 预报偏低:确定性预报 {om_today}{temp_symbol} 低于集合90%下限,更可能接近 {ens_median}{temp_symbol}。"
|
msg2 = f"⚡ 预报偏低:确定性预报 {om_today}{temp_symbol} 低于集合90%下限,更可能接近 {ens_median}{temp_symbol}。"
|
||||||
ai_features.append(msg2)
|
ai_features.append(msg2)
|
||||||
|
|
||||||
|
# === 数学概率计算(基于集合预报正态分布拟合)===
|
||||||
|
import math as _math
|
||||||
|
# 用 P10/P90 反推标准差: P10 = median - 1.28*sigma, P90 = median + 1.28*sigma
|
||||||
|
sigma = (ens_p90 - ens_p10) / 2.56
|
||||||
|
if sigma < 0.1: sigma = 0.1 # 防止除以零
|
||||||
|
mu = ens_median # 以集合中位数为中心
|
||||||
|
|
||||||
|
# 如果 DEB 融合值或多模型均值存在,用它们微调中心
|
||||||
|
if forecast_median is not None:
|
||||||
|
mu = (ens_median + forecast_median) / 2 # 取集合中位数和模型中位数的均值
|
||||||
|
|
||||||
|
# 简化的正态 CDF (不依赖 scipy)
|
||||||
|
def _norm_cdf(x, m, s):
|
||||||
|
return 0.5 * (1 + _math.erf((x - m) / (s * _math.sqrt(2))))
|
||||||
|
|
||||||
|
# 计算每个 WU 整数区间 [N-0.5, N+0.5) 的概率
|
||||||
|
center = round(mu)
|
||||||
|
candidates = range(center - 2, center + 3) # 5 个候选整数
|
||||||
|
probs = {}
|
||||||
|
for n in candidates:
|
||||||
|
p = _norm_cdf(n + 0.5, mu, sigma) - _norm_cdf(n - 0.5, mu, sigma)
|
||||||
|
if p > 0.01: # 只保留概率 > 1% 的
|
||||||
|
probs[n] = p
|
||||||
|
|
||||||
|
# 归一化
|
||||||
|
total_p = sum(probs.values())
|
||||||
|
if total_p > 0:
|
||||||
|
probs = {k: v / total_p for k, v in probs.items()}
|
||||||
|
|
||||||
|
# 格式化输出(按概率从高到低排列)
|
||||||
|
sorted_probs = sorted(probs.items(), key=lambda x: x[1], reverse=True)
|
||||||
|
prob_parts = [f"{int(t)}{temp_symbol}({p*100:.0f}%)" for t, p in sorted_probs[:4]]
|
||||||
|
if prob_parts:
|
||||||
|
prob_str = " | ".join(prob_parts)
|
||||||
|
insights.append(f"🎲 <b>结算概率</b>:{prob_str}")
|
||||||
|
ai_features.append(f"🎲 数学概率分布:{prob_str}")
|
||||||
|
|
||||||
# === 实测已超预报 & 趋势输出 ===
|
# === 实测已超预报 & 趋势输出 ===
|
||||||
if max_so_far is not None and forecast_high is not None:
|
if max_so_far is not None and forecast_high is not None:
|
||||||
if max_so_far > forecast_high + 0.5:
|
if max_so_far > forecast_high + 0.5:
|
||||||
|
|||||||
@@ -38,11 +38,7 @@ def get_ai_analysis(weather_insights: str, city_name: str, temp_symbol: str) ->
|
|||||||
2. **阻碍因子**:由于高湿度(>80%)、降水或全阴天气导致的升温失速。
|
2. **阻碍因子**:由于高湿度(>80%)、降水或全阴天气导致的升温失速。
|
||||||
3. **结算推演**:根据我提供给你的【博弈区间】以及【当前所处时段(是否过了最热期)】推断并告诉我最终结算温度落在哪个区间的希望更大。
|
3. **结算推演**:根据我提供给你的【博弈区间】以及【当前所处时段(是否过了最热期)】推断并告诉我最终结算温度落在哪个区间的希望更大。
|
||||||
4. **结算边界**:如果当前温度处于 X.5 这种进位/舍位边缘,需特别预警。
|
4. **结算边界**:如果当前温度处于 X.5 这种进位/舍位边缘,需特别预警。
|
||||||
5. **概率估算(极其重要,务必仔细推理)**:
|
5. **概率参考**:我已经通过数学模型计算好了结算概率分布(见【气象特征与事实】中的"数学概率分布"),请在你的逻辑分析中参考它来判断最终结算方向。
|
||||||
- WU 结算规则:实测最高温四舍五入到整数。即 X.5 以上进位,X.5 以下舍去。例如:3.5°C→4°C,3.4°C→3°C。
|
|
||||||
- 你必须先判断 DEB 融合值和各模型预报落在哪个 WU 取整区间内。例如 DEB=3.6°C 落在 [3.5, 4.5) 区间,对应 WU 结算 4°C。
|
|
||||||
- 然后综合集合预报 P10-P90 区间覆盖了哪些 WU 取整区间,按覆盖比例分配概率。
|
|
||||||
- 最终给出 2-4 个 WU 结算整数温度的概率(必须加起来 = 100%)。
|
|
||||||
|
|
||||||
【输出要求】
|
【输出要求】
|
||||||
1. **禁止废话**,整体控制在 200 字以内。
|
1. **禁止废话**,整体控制在 200 字以内。
|
||||||
@@ -51,7 +47,6 @@ def get_ai_analysis(weather_insights: str, city_name: str, temp_symbol: str) ->
|
|||||||
🤖 <b>Groq AI 决策</b>
|
🤖 <b>Groq AI 决策</b>
|
||||||
- 🎲 盘口: [必须明确指出最热时段(如:预计最热在 14:00-16:00)以及当前的博弈区间(如:锁定在 27°C 或 28°C 之间博弈)。若已明确降温,请直接给出死盘结论。]
|
- 🎲 盘口: [必须明确指出最热时段(如:预计最热在 14:00-16:00)以及当前的博弈区间(如:锁定在 27°C 或 28°C 之间博弈)。若已明确降温,请直接给出死盘结论。]
|
||||||
- 💡 逻辑: [用 2-3 句话深度分析:①当前机场实测的风速风向和云量对升温的促进/阻碍;②结合辐射、暖平流等动力因子判断温度还有多少上升空间;③最终是否能达到预报值。不要泛泛而谈,请使用具体数值。]
|
- 💡 逻辑: [用 2-3 句话深度分析:①当前机场实测的风速风向和云量对升温的促进/阻碍;②结合辐射、暖平流等动力因子判断温度还有多少上升空间;③最终是否能达到预报值。不要泛泛而谈,请使用具体数值。]
|
||||||
- 📊 概率: [列出最可能的 2-4 个 WU 结算整数温度及概率。注意:概率应反映实测最高温落入对应取整区间的可能性。格式:4°C(55%) | 3°C(35%) | 5°C(10%)]
|
|
||||||
- 🎯 置信度: [1-10]/10
|
- 🎯 置信度: [1-10]/10
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user