docs(predictV3): 添加predictV3算法优化研究文档和前端功能实现
- 完成Phase 11: predictV3算法优化研究文档,涵盖6个优化方向的技术分析 - 实现置信度评估功能,提供历史命中率、得分分布、多维度一致性置信度指标 - 扩展回测指标体系,新增NDCG@K、MRR、命中率分布等排名质量评估指标 - 优化转移概率算法,引入二阶马尔可夫链和多属性联合转移增强预测准确性 - 设计权重训练机制,支持网格搜索和遗传算法进行数据驱动的参数优化 - 集成组合特征挖掘功能,采用关联规则和序列模式发现号码间潜在关联 - 实现完整的前端交互界面,支持预测结果显示、置信度展示和回测验证功能 - 建立性能优化策略,包括预计算缓存、批量计算和降级策略保障响应速度
This commit is contained in:
@@ -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. 尾数±2(50%)</b>:上期正码和值尾数与当期特码尾数差≤2<br>' +
|
||||
' <b>6. 平均值±10(41.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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user