Files
skills-lottery-picker/skills/lottery_picker/model_full_report_dlt.py
T
CodeForge c4bb8632ca feat: 彩票技能统一输出格式 - 双色球/大乐透4块结构化输出标准对齐
- 新增 model_full_report_dlt.py: 大乐透专用全量报告脚本
- 统一4块结构: 回滚迭代→数据采集→推理分析→机选号码
- 统一术语: 前区/后区(大乐透) 对齐 红球/蓝球(双色球)
- 统一评分: TOP10前区+TOP5后区 归一化概率输出
- 更新 SKILL.md: 双色球/大乐透统一模板+文件结构
2026-07-30 06:04:12 +00:00

260 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
大乐透全量报告:与双色球 model_full_report.py 统一4块结构化输出
使用集成学习模型(5模型融合),输出格式与双色球完全对齐
"""
import json, math, os, datetime, hashlib, random, sys, io
from collections import Counter
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, "data")
OUTPUT_DIR = os.path.join(BASE_DIR, "model_output")
DLT_FILE = os.path.join(DATA_DIR, "dlt_history.json")
FEEDBACK_FILE = os.path.join(DATA_DIR, "feedback.json")
CONFIG_FILE = os.path.join(DATA_DIR, "config.json")
# ================================================================
# 加载数据
# ================================================================
data = json.load(open(DLT_FILE, "r", encoding="utf-8"))
records = []
historical_combos = set()
for r in data:
fronts = sorted([int(x) for x in r["reds"]])
backs = sorted([int(x) for x in r["blue"]]) if isinstance(r["blue"], list) else [int(r["blue"])]
if len(fronts) == 5 and all(1 <= n <= 35 for n in fronts) and len(backs) == 2 and all(1 <= n <= 12 for n in backs):
records.append({"issue": r["issue"], "fronts": fronts, "backs": backs, "date": r.get("date", "")})
historical_combos.add(tuple(fronts))
records.sort(key=lambda x: int(x["issue"]))
N = len(records)
latest = records[-1]
# ================================================================
# 加载回滚统计
# ================================================================
config = json.load(open(CONFIG_FILE, "r")) if os.path.exists(CONFIG_FILE) else {"iteration_count": 0}
feedback = json.load(open(FEEDBACK_FILE, "r")) if os.path.exists(FEEDBACK_FILE) else {
"iterations": [], "accuracy_history": [],
"ssq": {"total": 0, "correct_reds": 0, "correct_blues": 0, "best": 0, "profitable_wins": 0, "total_earnings": 0.0},
"dlt": {"total": 0, "correct_reds": 0, "correct_blues": 0, "best": 0, "profitable_wins": 0, "total_earnings": 0.0}
}
# ================================================================
# 计算下期信息
# ================================================================
prev_issue = latest["issue"]
prev_date = latest.get("date", "")
prev_fronts = latest["fronts"]
prev_backs = latest["backs"]
next_issue = str(int(prev_issue) + 1)
today = datetime.datetime.now()
draw_days = [1, 3, 6] # 周一、三、六
draw_time = "20:25"
draw_hour, draw_min = map(int, draw_time.split(":"))
now_hour, now_min = today.hour, today.minute
today_draw = today.isoweekday() in draw_days
time_past = (now_hour > draw_hour) or (now_hour == draw_hour and now_min >= draw_min)
if today_draw and not time_past:
delta = 0
else:
delta = 1
while (today + datetime.timedelta(days=delta)).isoweekday() not in draw_days:
delta += 1
next_draw = today + datetime.timedelta(days=delta)
next_draw_str = next_draw.strftime("%Y-%m-%d")
wd_map = {1:"周一",2:"周二",3:"周三",4:"周四",5:"周五",6:"周六",7:"周日"}
next_wd = wd_map.get(next_draw.isoweekday(), "")
# ================================================================
# 基础统计分析(与双色球贝叶斯后验对齐)
# ================================================================
# 前区频率统计
all_fronts = []
for r in records:
all_fronts.extend(r["fronts"])
front_freq = Counter(all_fronts)
total_fronts = len(all_fronts)
front_probs = {n: front_freq.get(n, 0) / total_fronts for n in range(1, 36)}
# 后区频率统计
all_backs = []
for r in records:
all_backs.extend(r["backs"])
back_freq = Counter(all_backs)
total_backs = len(all_backs)
back_probs = {n: back_freq.get(n, 0) / total_backs for n in range(1, 13)}
# 前区遗漏统计
front_last_seen = {n: 0 for n in range(1, 36)}
for i, r in enumerate(reversed(records)):
for n in r["fronts"]:
if front_last_seen[n] == 0:
front_last_seen[n] = i
# 后区遗漏统计
back_last_seen = {n: 0 for n in range(1, 13)}
for i, r in enumerate(reversed(records)):
for n in r["backs"]:
if back_last_seen[n] == 0:
back_last_seen[n] = i
# 综合评分 = 频率权重 × 0.4 + 遗漏回补 × 0.3 + 近期热度 × 0.3
front_scores = {}
for n in range(1, 36):
freq_score = front_probs.get(n, 0)
miss_score = min(1.0, front_last_seen[n] / 20) # 遗漏越大,回补概率越高
# 近期热度:最近10期出现次数
recent_count = sum(1 for r in records[-10:] if n in r["fronts"])
hot_score = recent_count / 10
front_scores[n] = 0.4 * freq_score + 0.3 * miss_score + 0.3 * hot_score
back_scores = {}
for n in range(1, 13):
freq_score = back_probs.get(n, 0)
miss_score = min(1.0, back_last_seen[n] / 15)
recent_count = sum(1 for r in records[-10:] if n in r["backs"])
hot_score = recent_count / 10
back_scores[n] = 0.4 * freq_score + 0.3 * miss_score + 0.3 * hot_score
# 归一化
total_front_score = sum(front_scores.values())
front_probs_norm = {n: s / total_front_score for n, s in front_scores.items()}
total_back_score = sum(back_scores.values())
back_probs_norm = {n: s / total_back_score for n, s in back_scores.items()}
# ================================================================
# 加载集成学习模块(抑制中间输出)
# ================================================================
sys.path.insert(0, BASE_DIR)
HAS_ENSEMBLE = False
ensemble_result = None
try:
# 临时重定向stdout以抑制集成学习的中间输出
old_stdout = sys.stdout
sys.stdout = io.StringIO()
from ensemble_learning import ensemble_recommendation
rule = {"name": "大乐透", "red_max": 35, "red_count": 5, "blue_max": 12, "blue_count": 2,
"draw_days": [1, 3, 6], "draw_time": "20:25", "source": "中国体育彩票"}
sorted_hist = sorted(records, key=lambda x: int(x["issue"]), reverse=True)[:100]
hist_for_ensemble = [{"issue": r["issue"], "reds": r["fronts"], "blue": r["backs"], "date": r.get("date", "")} for r in sorted_hist]
ensemble_result = ensemble_recommendation("dlt", hist_for_ensemble, rule, count=5)
sys.stdout = old_stdout
if ensemble_result and ensemble_result.get("recommendations"):
HAS_ENSEMBLE = True
except Exception as e:
sys.stdout = old_stdout
pass
# ================================================================
# 4块输出(与双色球统一格式)
# ================================================================
print("\n" + "=" * 60)
print(" [1/4] 回滚迭代")
print("=" * 60)
ver = config.get("iteration_count", 0)
stats = feedback.get("dlt", {})
total_recs = stats.get("total", 0)
profitable = stats.get("profitable_wins", 0)
win_rate = "%.1f%%" % (profitable / total_recs * 100) if total_recs > 0 else "0.0%"
earnings = stats.get("total_earnings", 0.0)
print(" 当前版本号: v%d (集成学习模型)" % ver)
print(" 版本胜率: %s (%d期推荐 / %d次盈利)" % (win_rate, total_recs, profitable))
print(" 累计中奖收益金额: RMB %.2f" % earnings)
# ==================== 第2块:数据采集 ====================
print("\n" + "=" * 60)
print(" [2/4] 数据采集")
print("=" * 60)
print(" 采集期数范围: 第%s期 ~ 第%s期(%d期)" % (records[0]["issue"], prev_issue, N))
print(" 上一期号: 第%s期" % prev_issue)
print(" 开奖日期: %s" % prev_date)
f_str = " ".join("%02d" % n for n in prev_fronts)
b_str = " ".join("%02d" % n for n in prev_backs)
print(" 开奖号码: 前区 %s 后区 %s" % (f_str, b_str))
# ==================== 第3块:推理分析 ====================
print("\n" + "=" * 60)
print(" [3/4] 推理分析(集成学习模型 | 数据源: 中国体育彩票)")
print("=" * 60)
# 步骤1: 前区频率分析 TOP10(与双色球"贝叶斯后验概率 TOP10红球"对齐)
top10_front = sorted(front_probs_norm.items(), key=lambda x: -x[1])[:10]
print(" >> 步骤1 - 频率分析(前区TOP10)")
print(" %s" % " ".join("%02d(%.4f)" % (n, s) for n, s in top10_front))
# 步骤2: 后区分析 TOP5
top5_back = sorted(back_probs_norm.items(), key=lambda x: -x[1])[:5]
print(" >> 步骤2 - 后区分析(TOP5)")
print(" %s" % " ".join("%02d(%.4f)" % (n, s) for n, s in top5_back))
# 步骤3: 模式识别
print(" >> 步骤3 - 模式识别")
# 统计历史奇偶比和大小比
oe_counter = Counter()
bs_counter = Counter()
for r in records[-30:]:
odd = sum(1 for n in r["fronts"] if n % 2 == 1)
even = 5 - odd
oe_counter[f"{odd}:{even}"] += 1
big = sum(1 for n in r["fronts"] if n > 17)
small = 5 - big
bs_counter[f"{big}:{small}"] += 1
most_oe = oe_counter.most_common(1)[0][0] if oe_counter else "3:2"
most_bs = bs_counter.most_common(1)[0][0] if bs_counter else "3:2"
sum_min = min(r["fronts"][0] + r["fronts"][1] for r in records[-30:])
sum_max = max(sum(r["fronts"]) for r in records[-30:])
print(" 奇偶比: %s | 大小比: %s | 和值区间: [%d, %d]" % (most_oe, most_bs, sum_min, sum_max))
# 步骤4: 权重体系
print(" >> 步骤4 - 权重体系(集成学习模型)")
if HAS_ENSEMBLE and ensemble_result.get("weights"):
weights = ensemble_result["weights"]
name_map = {'freq': '频率加权', 'bayes': '贝叶斯平滑', 'markov': '马尔可夫链',
'kmeans': 'K-Means聚类', 'residual': '残差回归'}
weight_parts = []
for m, w in sorted(weights.items(), key=lambda x: -x[1]):
weight_parts.append("%s%.2f%%" % (name_map.get(m, m), w * 100))
print(" %s" % " + ".join(weight_parts))
else:
print(" 频率40% + 遗漏30% + 热号30%")
# ==================== 第4块:机选号码 ====================
print("\n" + "=" * 60)
print(" [4/4] 机选号码(第%s期 | %s %s)" % (next_issue, next_draw_str, next_wd))
print("=" * 60)
if HAS_ENSEMBLE and ensemble_result.get("recommendations"):
recommendations = ensemble_result["recommendations"]
for i, r in enumerate(recommendations):
f_str = " ".join("%02d" % n for n in r["reds"])
b_str = " ".join("%02d" % n for n in r["blues"])
marker = " ⭐" if i == 0 else ""
print("\n 第%d组: 前区 %s 后区 %s%s" % (i + 1, f_str, b_str, marker))
print(" 得分:%.4f | 奇偶:%s | 大小:%s | 和:%d" % (
r["score"], r["odd_even"], r["big_small"], r["sum"]))
# 保存推荐
analysis_file = os.path.join(DATA_DIR, "analysis_dlt.json")
analysis = json.load(open(analysis_file, "r")) if os.path.exists(analysis_file) else {}
analysis["last_recommendation"] = {
"fronts": recommendations[0]["reds"],
"backs": recommendations[0]["blues"],
"generated_at": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"model_version": "ensemble_v7"
}
json.dump(analysis, open(analysis_file, "w"), ensure_ascii=False, indent=2)
else:
print(" [⚠️ 无法生成推荐,请检查数据]")
print("\n" + "=" * 60)
print(" ⚠️ 免责声明: 本推荐仅基于历史统计建模的相对概率评分,")
print(" 不预测下期开奖,不保证中奖。彩票是独立随机事件。")
print("=" * 60)
print("\n 开奖后把实际号码发我,帮你回滚迭代校正精度 🍀")