docs(predictV3): 添加predictV3算法优化研究文档和前端功能实现

- 完成Phase 11: predictV3算法优化研究文档,涵盖6个优化方向的技术分析
- 实现置信度评估功能,提供历史命中率、得分分布、多维度一致性置信度指标
- 扩展回测指标体系,新增NDCG@K、MRR、命中率分布等排名质量评估指标
- 优化转移概率算法,引入二阶马尔可夫链和多属性联合转移增强预测准确性
- 设计权重训练机制,支持网格搜索和遗传算法进行数据驱动的参数优化
- 集成组合特征挖掘功能,采用关联规则和序列模式发现号码间潜在关联
- 实现完整的前端交互界面,支持预测结果显示、置信度展示和回测验证功能
- 建立性能优化策略,包括预计算缓存、批量计算和降级策略保障响应速度
This commit is contained in:
2026-05-01 23:17:24 +08:00
parent 02b3ff3a22
commit 8b2590c5b5
26 changed files with 5407 additions and 2 deletions
+203
View File
@@ -107,6 +107,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
$(document).off('click', '.btn-predict').on('click', '.btn-predict', function () {
Controller.api.showPredictDialog();
});
// 正码关联预测按钮事件
$(document).off('click', '.btn-normal-relation').on('click', '.btn-normal-relation', function () {
Controller.api.showNormalRelationDialog();
});
},
add: function () {
Controller.api.bindevent();
@@ -1960,6 +1965,204 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
html += '</div>';
$('#predict-result', layero).html(html);
},
/**
* 显示正码关联预测弹窗(修正版)
* 核心规律:上期正码 → 当期特码
*/
showNormalRelationDialog: function () {
var html = '<div style="padding:20px;">' +
'<div style="margin-bottom:15px;background:#e8f5e9;border:1px solid #4caf50;padding:10px;border-radius:6px;">' +
' <div style="font-size:13px;font-weight:bold;color:#2e7d32;margin-bottom:8px;"><i class="fa fa-link"></i> 正码关联预测算法(修正版)</div>' +
' <div style="font-size:12px;color:#666;">' +
' <b>核心逻辑</b>:用<b>上期正码(num1-6)</b>预测<b>当期特码(num7)</b><br>' +
' <b>1. 覆盖区间规律(91.44%</b>:当期特码在上期正码覆盖的细区间内<br>' +
' <b>2. 特码区间转移(77.54%</b>:基于上期特码区间预测当期特码大区间<br>' +
' <b>3. 双波色预测(69.52%</b>:当期特码波色在上期正码前2种主导波色内<br>' +
' <b>4. 正码±3距离(59.36%</b>:当期特码与上期正码某号码距离≤3<br>' +
' <b>5. 尾数±250%</b>:上期正码和值尾数与当期特码尾数差≤2<br>' +
' <b>6. 平均值±1041.98%</b>:当期特码在上期正码平均值±10范围' +
' </div>' +
'</div>' +
'<div class="form-group">' +
' <label>回测期数:</label>' +
' <input type="number" id="nr-periods" class="form-control" value="100" min="30" max="500" style="width:120px;display:inline-block;">' +
' <label style="margin-left:15px;">目标期号(可选):</label>' +
' <input type="text" id="nr-target" class="form-control" placeholder="如2026120" style="width:150px;display:inline-block;">' +
' <button class="btn btn-primary" id="btn-nr-query" style="margin-left:10px;"><i class="fa fa-search"></i> 查询</button>' +
'</div>' +
'<div id="nr-result" style="margin-top:15px;"></div>' +
'</div>';
Layer.open({
type: 1,
title: '正码关联预测(上期正码→当期特码)',
area: ['900px', '750px'],
content: html,
shadeClose: true,
success: function (layero, index) {
$('#btn-nr-query', layero).on('click', function () {
Controller.api.queryNormalRelation(layero);
});
// 自动执行一次查询
Controller.api.queryNormalRelation(layero);
}
});
},
/**
* 查询正码关联预测
*/
queryNormalRelation: function (layero) {
var $btn = $('#btn-nr-query', layero);
$btn.prop('disabled', true);
$('#nr-result', layero).html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> 正在分析...</div>');
var periods = parseInt($('#nr-periods', layero).val()) || 100;
var targetExpect = $('#nr-target', layero).val().trim();
$.ajax({
url: 'history/predictByNormalRelation',
type: 'GET',
data: { periods: periods, target_expect: targetExpect },
dataType: 'json',
success: function (ret) {
if (ret.code == 1) {
Controller.api.renderNormalRelation(ret.data, layero);
} else {
$('#nr-result', layero).html('<div class="alert alert-danger">' + (ret.msg || '查询失败') + '</div>');
}
},
error: function () {
$('#nr-result', layero).html('<div class="alert alert-danger">查询失败</div>');
},
complete: function () {
$btn.prop('disabled', false);
}
});
},
/**
* 渲染正码关联预测结果
*/
renderNormalRelation: function (data, layero) {
if (!data || !data.predictions || data.predictions.length === 0) {
$('#nr-result', layero).html('<div class="alert alert-info">无预测结果</div>');
return;
}
var analysis = data.analysis || {};
var predictions = data.predictions;
var hitInfo = data.hit_info;
var backtest = data.backtest;
var html = '';
// 分析信息
html += '<div style="background:#f5f5f5;padding:10px;border-radius:6px;margin-bottom:15px;">';
html += '<div style="font-size:13px;font-weight:bold;margin-bottom:8px;"><i class="fa fa-info-circle"></i> 上期开奖信息(预测基准)</div>';
html += '<div style="font-size:12px;">';
html += '期号:<b>' + analysis.last_expect + '</b> | ';
html += '正码:<b>' + analysis.last_normals.join(', ') + '</b> | ';
html += '特码:<b>' + analysis.last_special + '</b><br>';
html += '正码范围:' + analysis.normal_min + ' ~ ' + analysis.normal_max + ' | ';
html += '平均值:' + analysis.normal_avg + ' | ';
html += '和值:' + analysis.normal_sum + '<br>';
html += '正码波色:<b>' + (analysis.top2_colors || analysis.normal_colors || []).join('/') + '</b> | ';
html += '覆盖区间:' + (analysis.normal_fine_zones || analysis.normal_zones || []).map(function(z) {
return ['1-10','11-20','21-30','31-40','41-49'][z];
}).join(',');
html += '</div></div>';
// 预测号码展示
html += '<div style="margin-bottom:15px;">';
html += '<div style="font-size:13px;font-weight:bold;margin-bottom:8px;"><i class="fa fa-star"></i> 推荐号码(Top 15</div>';
html += '<div style="display:flex;flex-wrap:wrap;gap:8px;">';
for (var i = 0; i < predictions.length; i++) {
var p = predictions[i];
var colorHex = Controller.api.getColorByNum(p.num);
var animal = Controller.api.animalMap[p.num] || '';
var bgColor = '#fff';
var borderColor = '1px solid #ddd';
if (i < 5) {
bgColor = '#fff8e1';
borderColor = '2px solid #ffc107';
}
html += '<div style="background:' + bgColor + ';border:' + borderColor + ';padding:8px;border-radius:8px;min-width:90px;text-align:center;">';
html += '<span style="display:inline-block;width:36px;height:36px;line-height:36px;border-radius:50%;color:#fff;background:' + colorHex + ';font-weight:bold;font-size:16px;">' + p.num + '</span>';
html += '<div style="font-size:10px;color:#666;">' + animal + '</div>';
html += '<div style="font-size:11px;color:#2e7d32;font-weight:bold;">得分:' + p.score + '</div>';
html += '<div style="font-size:9px;color:#999;">';
html += (p.color_in_top2 || p.color_match) ? '✓波色 ' : '';
html += '距离' + (p.min_distance || 0);
html += '</div>';
html += '</div>';
}
html += '</div></div>';
// 规律命中情况(如果有回测)
if (backtest) {
html += '<div style="background:#e3f2fd;padding:10px;border-radius:6px;margin-bottom:15px;">';
html += '<div style="font-size:13px;font-weight:bold;margin-bottom:8px;"><i class="fa fa-chart-line"></i> 回测验证(最近' + backtest.periods + '期)</div>';
html += '<div style="font-size:12px;">';
html += '命中率(Top15内):<b style="color:#2e7d32;">' + backtest.hit_rate + '%</b> (' + backtest.hits + '/' + backtest.periods + ')<br>';
html += '平均排名:<b>' + backtest.avg_rank + '</b> / 49<br>';
html += '<span style="color:#666;font-size:11px;">注:命中率越高越好,平均排名越低越好</span>';
html += '</div>';
// 显示前50期命中详情表格
if (backtest.details && backtest.details.length > 0) {
html += '<div style="margin-top:10px;max-height:300px;overflow-y:auto;">';
html += '<table class="table table-striped table-bordered" style="font-size:11px;">';
html += '<thead><tr><th>期号</th><th>特码</th><th>排名</th><th>命中</th></tr></thead>';
html += '<tbody>';
for (var d = 0; d < backtest.details.length; d++) {
var det = backtest.details[d];
var hitBadge = det.hit ? '<span style="color:#2e7d32;font-weight:bold;">✓</span>' : '<span style="color:#c62828;">✗</span>';
var rankColor = det.rank <= 5 ? '#2e7d32' : (det.rank <= 15 ? '#ff9800' : '#c62828');
html += '<tr>';
html += '<td>' + det.expect + '</td>';
html += '<td>' + det.actual + '</td>';
html += '<td><b style="color:' + rankColor + ';">' + det.rank + '</b></td>';
html += '<td>' + hitBadge + '</td>';
html += '</tr>';
}
html += '</tbody></table>';
html += '</div>';
}
html += '</div>';
}
// 实际命中情况(如果有目标期号)
if (hitInfo) {
var hitBg = hitInfo.hit ? '#e8f5e9' : '#ffebee';
var hitColor = hitInfo.hit ? '#2e7d32' : '#c62828';
html += '<div style="background:' + hitBg + ';padding:10px;border-radius:6px;margin-bottom:15px;">';
html += '<div style="font-size:13px;font-weight:bold;color:' + hitColor + ';">';
html += hitInfo.hit ? '✓ 命中!排名:' + hitInfo.rank_in_top + ' / 15' : '✗ 未命中,排名:' + hitInfo.rank_in_all + ' / 49';
html += '</div>';
html += '<div style="font-size:12px;">实际特码:<b>' + hitInfo.actual_num + '</b> (' + hitInfo.actual_color + '/' + hitInfo.actual_animal + ') 期号:' + hitInfo.actual_expect + '</div>';
html += '</div>';
}
// 规律说明表
if (analysis.rules) {
html += '<div style="margin-top:15px;">';
html += '<div style="font-size:13px;font-weight:bold;margin-bottom:8px;"><i class="fa fa-table"></i> 规律命中率表</div>';
html += '<table class="table table-bordered" style="font-size:12px;">';
html += '<tr><th>规律名称</th><th>命中率</th><th>说明</th></tr>';
for (var r = 0; r < analysis.rules.length; r++) {
var rule = analysis.rules[r];
html += '<tr><td>' + rule.name + '</td><td><b style="color:#2e7d32;">' + rule.rate + '</b></td><td>' + rule.desc + '</td></tr>';
}
html += '</table></div>';
}
$('#nr-result', layero).html(html);
}
}
};