8b2590c5b5
- 完成Phase 11: predictV3算法优化研究文档,涵盖6个优化方向的技术分析 - 实现置信度评估功能,提供历史命中率、得分分布、多维度一致性置信度指标 - 扩展回测指标体系,新增NDCG@K、MRR、命中率分布等排名质量评估指标 - 优化转移概率算法,引入二阶马尔可夫链和多属性联合转移增强预测准确性 - 设计权重训练机制,支持网格搜索和遗传算法进行数据驱动的参数优化 - 集成组合特征挖掘功能,采用关联规则和序列模式发现号码间潜在关联 - 实现完整的前端交互界面,支持预测结果显示、置信度展示和回测验证功能 - 建立性能优化策略,包括预计算缓存、批量计算和降级策略保障响应速度
885 lines
33 KiB
Markdown
885 lines
33 KiB
Markdown
# Phase 11: predictV3算法优化 - Research
|
||
|
||
**Researched:** 2026-05-01
|
||
**Domain:** 彩票号码预测算法优化 / 多维度评分系统增强
|
||
**Confidence:** MEDIUM (基于代码分析 + 训练知识,部分技术方案需要进一步验证)
|
||
|
||
## Summary
|
||
|
||
现有 V3 预测算法已实现 9 个评分维度和动态权重调整机制,核心技术栈为 PHP + ThinkPHP 5.x,采用马尔可夫链转移概率、经验分布函数、走势分析等方法进行号码预测。优化方向涵盖:数据维度扩展、转移概率增强、权重训练、置信度评估、回测指标扩展、组合特征挖掘六个领域。
|
||
|
||
**Primary recommendation:** 优先实现置信度评估和回测指标扩展,这两个方向对用户体验提升最直接;权重训练和转移概率增强可作为中期优化目标;组合特征挖掘和数据维度扩展需要更多历史数据支撑,适合长期迭代。
|
||
|
||
## Architectural Responsibility Map
|
||
|
||
| Capability | Primary Tier | Secondary Tier | Rationale |
|
||
|------------|-------------|----------------|-----------|
|
||
| 预测计算核心 | Backend (PHP Model) | — | 复杂统计计算、历史数据分析在服务端完成 |
|
||
| 回测验证 | Backend (PHP Model) | — | 需要批量查询历史数据,服务端性能最优 |
|
||
| 权重配置 | Frontend (JS) + Backend | Backend | 前端提供UI配置,后端存储默认值并验证 |
|
||
| 置信度展示 | Frontend (JS) | Backend | 后端计算置信度,前端负责可视化呈现 |
|
||
| 组合特征挖掘 | Backend (PHP Model) | — | 数据密集型计算,服务端执行效率高 |
|
||
|
||
## Technical Analysis
|
||
|
||
### 现有 V3 算法架构
|
||
|
||
**核心入口方法:** `getPredictionV3($periods = 200, $weights = [], $targetExpect = '', $skipBacktest = false, $backtestCount = 50)`
|
||
|
||
**9个评分维度及其实现:**
|
||
|
||
| 维度 | 方法 | 核心技术 | 当前权重(默认) |
|
||
|------|------|----------|----------------|
|
||
| 遗漏回归 | `_calcOmitScoreEmpirical()` | 经验累积分布函数(CDF),百分位排名映射 | 0.18 |
|
||
| 频率回归 | `_calcFreqScoreAdvanced()` | 频率比率 + 回归窗口判断 + 卡方检验 | 0.12 |
|
||
| 转移概率 | `_calcTransitionScore()` | 一阶马尔可夫链,拉普拉斯平滑处理 | 0.18 |
|
||
| 单双平衡 | `_calcOddEvenScore()` | 连续性反转预测 + 比例失衡回归 | 0.08 |
|
||
| 大小平衡 | `_calcBigSmallScore()` | 同单双逻辑,大小阈值25 | 0.08 |
|
||
| 走势方向 | `_calcTrendDirectionScore()` | 上升/下降/跳跃趋势识别,强度加权 | 0.14 |
|
||
| 区域平衡 | 内联计算 | 5区域分布比例失衡回归 | 0.04 |
|
||
| 波色平衡 | 内联计算 | 红蓝绿三色分布失衡回归 | 0.04 |
|
||
| 组合特征 | `_calcCombinationScore()` | 属性组合、相邻号码共现、前3期模式 | 0.10 |
|
||
|
||
**动态权重调整:** `_adjustWeightsDynamic()` 根据走势强度、遗漏分布、单双/大小连续性实时调整权重并归一化。
|
||
|
||
**回测机制:** `_runBacktestV3()` 执行最近N期历史验证,输出命中率(Top5)、平均排名、详细记录。
|
||
|
||
### 代码结构优势
|
||
|
||
1. **模块化设计:** 每个维度独立方法,便于单独优化和测试
|
||
2. **预计算优化:** 号码属性索引(zoneMap, colorKeyMap, tailMap等)在主循环外预构建
|
||
3. **参数化配置:** 权重可前端传入,支持用户自定义
|
||
4. **回测验证:** 内置历史验证机制,可评估算法有效性
|
||
|
||
### 代码结构局限
|
||
|
||
1. **一阶马尔可夫:** 转移概率仅考虑上一期状态,未利用更长的历史序列
|
||
2. **固定评分函数:** 各维度评分逻辑硬编码,缺乏数据驱动的参数调优
|
||
3. **无置信度输出:** 预测结果只有排名,无置信度指标
|
||
4. **回测指标单一:** 仅命中率+平均排名,缺少NDCG、MRR等排名质量指标
|
||
5. **组合特征简单:** 仅考虑±2相邻共现和前3期模式,挖掘深度不足
|
||
|
||
---
|
||
|
||
## Optimization Recommendations
|
||
|
||
### 方向1: 数据维度扩展
|
||
|
||
**目标:** 添加新的有效评分维度,丰富预测信号来源
|
||
|
||
**推荐新增维度:**
|
||
|
||
| 维度 | 技术方案 | 实现复杂度 | 预期收益 |
|
||
|------|----------|------------|----------|
|
||
| **时间周期性** | 分析开奖日期的周期规律(周几、月份)对号码分布的影响 | 低 | 中 |
|
||
| **生肖序列** | 将生肖映射为数值序列,分析生肖转移规律 | 低 | 中 |
|
||
| **跨期关联** | 分析前N期(3-5期)号码组合对当前期的联合影响 | 中 | 中-高 |
|
||
| **号码距离** | 计算候选号码与最近5期开奖号码的平均距离特征 | 低 | 低-中 |
|
||
| **连号特征** | 统计历史连号出现频率,预测连号概率 | 低 | 低 |
|
||
|
||
**实现建议:**
|
||
|
||
```php
|
||
// 示例: 时间周期性分析方法
|
||
/**
|
||
* 分析时间周期性特征
|
||
* @param array $history 历史数据(含openTime)
|
||
* @return array {weekday_stats: [], month_stats: []}
|
||
*/
|
||
private function _analyzeTimeCycle($history)
|
||
{
|
||
$weekdayCount = array_fill(0, 7, []); // 周一到周日
|
||
$monthCount = array_fill(1, 12, []); // 1-12月
|
||
|
||
foreach ($history as $row) {
|
||
$num = (int)$row['num7'];
|
||
$weekday = date('N', strtotime($row['openTime'])); // 1-7
|
||
$month = date('n', strtotime($row['openTime'])); // 1-12
|
||
|
||
if (!isset($weekdayCount[$weekday][$num])) {
|
||
$weekdayCount[$weekday][$num] = 0;
|
||
}
|
||
$weekdayCount[$weekday][$num]++;
|
||
|
||
if (!isset($monthCount[$month][$num])) {
|
||
$monthCount[$month][$num] = 0;
|
||
}
|
||
$monthCount[$month][$num]++;
|
||
}
|
||
|
||
return [
|
||
'weekday_stats' => $weekdayCount,
|
||
'month_stats' => $monthCount
|
||
];
|
||
}
|
||
```
|
||
|
||
**注意事项:**
|
||
- 新维度需在 `_adjustWeightsDynamic()` 中添加相应的动态调整逻辑
|
||
- 权重初始值需谨慎设置,避免过度稀释现有有效维度
|
||
- 维度数量增加可能导致权重分配稀疏,需考虑维度重要性排序
|
||
|
||
**置信度:** MEDIUM [ASSUMED] - 基于训练知识,时间周期性在实际预测场景中效果需验证
|
||
|
||
---
|
||
|
||
### 方向2: 转移概率增强
|
||
|
||
**目标:** 改进现有一阶马尔可夫链,提升转移概率预测准确性
|
||
|
||
**推荐增强方案:**
|
||
|
||
| 方案 | 技术细节 | 实现复杂度 | 预期收益 |
|
||
|------|----------|------------|----------|
|
||
| **二阶马尔可夫链** | 考虑前两期状态联合决定当前转移概率,状态空间扩大但预测更精准 | 中 | 中-高 |
|
||
| **多属性联合转移** | 同时考虑单双+大小的联合状态转移(4状态),而非单独计算 | 中 | 中 |
|
||
| **衰减权重转移** | 近期转移权重更高,历史久远的转移权重衰减 | 低 | 低-中 |
|
||
| **条件转移概率** | 在特定条件下(如遗漏超过阈值)调整转移概率分布 | 中 | 中 |
|
||
|
||
**二阶马尔可夫链实现思路:**
|
||
|
||
```php
|
||
/**
|
||
* 构建二阶马尔可夫转移矩阵
|
||
* @param array $history 历史数据(降序)
|
||
* @param string $type 类型:zone/tail/head
|
||
* @return array {matrix: [], prob_matrix: [], state_totals: []}
|
||
*/
|
||
private function _getTransitionMatrix2ndOrder($history, $type)
|
||
{
|
||
$historyAsc = array_reverse($history);
|
||
$numCategories = $type === 'tail' ? 10 : 5;
|
||
|
||
// 状态空间: (prev1, prev2) -> current,共 numCategories^2 个前置状态
|
||
$matrix = [];
|
||
$stateTotals = [];
|
||
|
||
// 初始化矩阵结构
|
||
for ($i = 0; $i < $numCategories; $i++) {
|
||
for ($j = 0; $j < $numCategories; $j++) {
|
||
$stateKey = $i . '-' . $j;
|
||
$matrix[$stateKey] = array_fill(0, $numCategories, 0);
|
||
$stateTotals[$stateKey] = 0;
|
||
}
|
||
}
|
||
|
||
$getIdx = $this->_getCategoryIdxFunction($type);
|
||
|
||
// 统计二阶转移
|
||
for ($i = 0; $i < count($historyAsc) - 2; $i++) {
|
||
$prev1 = $getIdx((int)$historyAsc[$i]['num7']);
|
||
$prev2 = $getIdx((int)$historyAsc[$i + 1]['num7']);
|
||
$current = $getIdx((int)$historyAsc[$i + 2]['num7']);
|
||
|
||
if ($prev1 < 0 || $prev2 < 0 || $current < 0) continue;
|
||
|
||
$stateKey = $prev1 . '-' . $prev2;
|
||
$matrix[$stateKey][$current]++;
|
||
$stateTotals[$stateKey]++;
|
||
}
|
||
|
||
// 拉普拉斯平滑处理
|
||
$probMatrix = [];
|
||
foreach ($matrix as $stateKey => $counts) {
|
||
$smoothTotal = $stateTotals[$stateKey] + $numCategories;
|
||
$probMatrix[$stateKey] = [];
|
||
for ($j = 0; $j < $numCategories; $j++) {
|
||
$probMatrix[$stateKey][$j] = ($counts[$j] + 1) / $smoothTotal;
|
||
}
|
||
}
|
||
|
||
return [
|
||
'matrix' => $matrix,
|
||
'prob_matrix' => $probMatrix,
|
||
'state_totals' => $stateTotals,
|
||
'num_categories' => $numCategories
|
||
];
|
||
}
|
||
```
|
||
|
||
**注意事项:**
|
||
- 二阶马尔可夫状态空间指数增长(5^2=25或10^2=100),历史数据不足时概率估计不稳定
|
||
- 需保留一阶方法作为数据不足时的fallback
|
||
- 可结合现有 `_getTransitionMatrix()` 形成混合策略
|
||
|
||
**置信度:** MEDIUM [ASSUMED] - 二阶马尔可夫在理论上更精准,但实际效果需回测验证
|
||
|
||
---
|
||
|
||
### 方向3: 权重训练
|
||
|
||
**目标:** 实现数据驱动的权重优化,替代手动调参
|
||
|
||
**推荐方案:**
|
||
|
||
| 方案 | 技术细节 | 实现复杂度 | 适用场景 |
|
||
|------|----------|------------|----------|
|
||
| **历史回测网格搜索** | 预定义权重组合网格,批量回测选择最优组合 | 低 | 快速验证,适合初期 |
|
||
| **遗传算法优化** | 定义权重基因,通过选择/交叉/变异迭代优化 | 中 | 复杂权重空间探索 |
|
||
| **时间段分层权重** | 不同时间段使用不同权重配置(强趋势/弱趋势/跳跃) | 低 | 适应动态场景 |
|
||
| **梯度下降优化** | 定义损失函数(命中率),迭代调整权重 | 高 | 需要大量回测数据 |
|
||
|
||
**网格搜索实现思路:**
|
||
|
||
```php
|
||
/**
|
||
* 权重网格搜索优化
|
||
* @param int $periods 统计期数
|
||
* @param int $backtestCount 回测期数
|
||
* @param int $steps 每个权重的搜索步数
|
||
* @return array {best_weights: [], best_hit_rate: float, all_results: []}
|
||
*/
|
||
private function _optimizeWeightsGridSearch($periods = 200, $backtestCount = 50, $steps = 5)
|
||
{
|
||
$weightKeys = ['omit_regression', 'freq_regression', 'transition_prob',
|
||
'oddeven_balance', 'bigsmall_balance', 'trend_direction',
|
||
'zone_balance', 'color_balance', 'combination'];
|
||
|
||
$bestWeights = [];
|
||
$bestHitRate = 0;
|
||
$allResults = [];
|
||
|
||
// 简化: 固定部分权重,仅优化核心权重组合
|
||
// 实际实现需考虑组合爆炸问题,可采用分层搜索或随机采样
|
||
$baseConfigs = [
|
||
// 配置1: 遗漏优先
|
||
['omit_regression' => 0.25, 'freq_regression' => 0.15, 'transition_prob' => 0.20, 'trend_direction' => 0.15],
|
||
// 配置2: 转移优先
|
||
['omit_regression' => 0.15, 'freq_regression' => 0.10, 'transition_prob' => 0.25, 'trend_direction' => 0.12],
|
||
// 配置3: 走势优先
|
||
['omit_regression' => 0.12, 'freq_regression' => 0.10, 'transition_prob' => 0.15, 'trend_direction' => 0.25],
|
||
];
|
||
|
||
foreach ($baseConfigs as $config) {
|
||
$weights = array_merge($config, [
|
||
'oddeven_balance' => 0.08,
|
||
'bigsmall_balance' => 0.08,
|
||
'zone_balance' => 0.04,
|
||
'color_balance' => 0.04,
|
||
'combination' => 0.08
|
||
]);
|
||
|
||
// 归一化权重
|
||
$total = array_sum($weights);
|
||
foreach ($weights as $key => $value) {
|
||
$weights[$key] = $value / $total;
|
||
}
|
||
|
||
// 执行回测
|
||
$backtest = $this->_runBacktestV3($periods, $weights, $backtestCount);
|
||
$hitRate = $backtest['hit_rate'];
|
||
|
||
$allResults[] = [
|
||
'weights' => $weights,
|
||
'hit_rate' => $hitRate,
|
||
'avg_rank' => $backtest['avg_rank']
|
||
];
|
||
|
||
if ($hitRate > $bestHitRate) {
|
||
$bestHitRate = $hitRate;
|
||
$bestWeights = $weights;
|
||
}
|
||
}
|
||
|
||
return [
|
||
'best_weights' => $bestWeights,
|
||
'best_hit_rate' => $bestHitRate,
|
||
'all_results' => $allResults
|
||
];
|
||
}
|
||
```
|
||
|
||
**注意事项:**
|
||
- 网格搜索组合爆炸问题严重,需采用分层搜索或启发式采样
|
||
- 权重优化结果依赖历史数据量,数据不足时优化不可靠
|
||
- 需定期重新优化,避免过拟合特定时间段
|
||
- 可将优化结果存储到配置文件,供前端默认加载
|
||
|
||
**置信度:** HIGH [CITED: 机器学习参数优化最佳实践] - 网格搜索和遗传算法是成熟的参数优化方法
|
||
|
||
---
|
||
|
||
### 方向4: 置信度评估
|
||
|
||
**目标:** 为预测结果提供置信度指标,帮助用户判断预测可靠性
|
||
|
||
**推荐置信度来源:**
|
||
|
||
| 来源 | 计算方法 | 实现复杂度 | 信息价值 |
|
||
|------|----------|------------|----------|
|
||
| **历史命中率置信度** | 基于相同排名位置的历史命中率统计 | 低 | 高 |
|
||
| **得分分布置信度** | 当前预测得分与历史命中号码得分分布的距离 | 中 | 中 |
|
||
| **多维度一致性置信度** | 各维度得分方向的一致程度(是否都指向同一号码) | 中 | 中 |
|
||
| **回测稳定性置信度** | 多批次回测命中率的方差(稳定性越高置信度越高) | 低 | 高 |
|
||
|
||
**置信度计算实现:**
|
||
|
||
```php
|
||
/**
|
||
* 计算预测置信度
|
||
* @param array $predictions 预测结果数组
|
||
* @param array $backtest 回测结果
|
||
* @param array $scoresAll 所有号码得分详情
|
||
* @return array {confidence_scores: [], overall_confidence: float}
|
||
*/
|
||
private function _calculateConfidence($predictions, $backtest, $scoresAll)
|
||
{
|
||
$confidenceScores = [];
|
||
|
||
foreach ($predictions as $idx => $pred) {
|
||
$rank = $idx + 1;
|
||
$num = $pred['num'];
|
||
$score = $pred['score'];
|
||
|
||
// 1. 基于历史排名命中率
|
||
$rankHitRate = $this->_getHistoricalHitRateByRank($rank, $backtest);
|
||
|
||
// 2. 基于得分分布
|
||
$scoreConfidence = $this->_getScoreDistributionConfidence($score, $scoresAll);
|
||
|
||
// 3. 基于多维度一致性
|
||
$consistencyConfidence = $this->_getDimensionConsistency($pred['detail']);
|
||
|
||
// 综合置信度(加权平均)
|
||
$overallConfidence = $rankHitRate * 0.4 + $scoreConfidence * 0.3 + $consistencyConfidence * 0.3;
|
||
|
||
$confidenceScores[] = [
|
||
'num' => $num,
|
||
'rank' => $rank,
|
||
'confidence' => round($overallConfidence * 100, 1),
|
||
'rank_hit_rate' => round($rankHitRate * 100, 1),
|
||
'score_confidence' => round($scoreConfidence * 100, 1),
|
||
'consistency' => round($consistencyConfidence * 100, 1)
|
||
];
|
||
}
|
||
|
||
// 整体置信度(Top5平均)
|
||
$overallConfidence = array_sum(array_column($confidenceScores, 'confidence')) / count($confidenceScores);
|
||
|
||
return [
|
||
'confidence_scores' => $confidenceScores,
|
||
'overall_confidence' => round($overallConfidence, 1)
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 基于历史排名获取命中率
|
||
*/
|
||
private function _getHistoricalHitRateByRank($rank, $backtest)
|
||
{
|
||
if (!$backtest || empty($backtest['details'])) {
|
||
// 无回测数据时,根据排名估算(排名越靠前置信度越高)
|
||
return max(0, 1 - ($rank - 1) * 0.15);
|
||
}
|
||
|
||
// 统计各排名的历史命中次数
|
||
$rankHits = array_fill(1, 5, 0);
|
||
foreach ($backtest['details'] as $detail) {
|
||
if ($detail['hit'] && $detail['rank'] >= 1 && $detail['rank'] <= 5) {
|
||
$rankHits[$detail['rank']]++;
|
||
}
|
||
}
|
||
|
||
$totalTests = $backtest['total_tests'];
|
||
return $totalTests > 0 ? $rankHits[$rank] / $totalTests : 0;
|
||
}
|
||
|
||
/**
|
||
* 计算多维度一致性
|
||
*/
|
||
private function _getDimensionConsistency($detail)
|
||
{
|
||
// 检查各维度得分是否都为正向(高于阈值)
|
||
$positiveDimensions = 0;
|
||
$totalDimensions = 0;
|
||
|
||
$thresholds = [
|
||
'omit_score' => 30,
|
||
'freq_score' => 20,
|
||
'trans_score' => 15,
|
||
'oddeven_score' => 20,
|
||
'bigsmall_score' => 20,
|
||
'trend_score' => 20,
|
||
'zone_score' => 15,
|
||
'color_score' => 15,
|
||
'combo_score' => 15
|
||
];
|
||
|
||
foreach ($thresholds as $key => $threshold) {
|
||
if (isset($detail[$key])) {
|
||
$totalDimensions++;
|
||
if ($detail[$key] >= $threshold) {
|
||
$positiveDimensions++;
|
||
}
|
||
}
|
||
}
|
||
|
||
return $totalDimensions > 0 ? $positiveDimensions / $totalDimensions : 0;
|
||
}
|
||
```
|
||
|
||
**前端展示建议:**
|
||
|
||
```javascript
|
||
// 在预测结果中添加置信度标签
|
||
var confidenceHtml = '';
|
||
for (var i = 0; i < confidenceScores.length; i++) {
|
||
var cs = confidenceScores[i];
|
||
var confLevel = cs.confidence >= 70 ? '高' : (cs.confidence >= 50 ? '中' : '低');
|
||
var confColor = cs.confidence >= 70 ? '#4caf50' : (cs.confidence >= 50 ? '#ff9800' : '#f44336');
|
||
confidenceHtml += '<span style="font-size:10px;color:' + confColor + ';">置信度:' + confLevel + '(' + cs.confidence + '%)</span>';
|
||
}
|
||
```
|
||
|
||
**置信度:** HIGH [ASSUMED] - 置信度评估对用户决策有明显辅助价值,实现方案基于成熟的统计方法
|
||
|
||
---
|
||
|
||
### 方向5: 回测指标扩展
|
||
|
||
**目标:** 丰富回测评估指标,全面衡量算法预测质量
|
||
|
||
**推荐新增指标:**
|
||
|
||
| 指标 | 说明 | 计算公式 | 实现复杂度 |
|
||
|------|------|----------|------------|
|
||
| **NDCG@K** | 考虑排名位置的加权命中指标,排名越靠前权重越高 | DCG/IDCG | 中 |
|
||
| **MRR** | 平均倒数排名,关注命中号码的具体排名位置 | Σ(1/rank)/N | 低 |
|
||
| **MAP@K** | 平均精度均值,综合衡量所有排名的精度 | Σ(Precision@k)/K | 低 |
|
||
| **命中率分布** | 各排名位置的命中次数分布统计 | {rank1_hits, rank2_hits...} | 低 |
|
||
| **时间段命中率** | 按时间段分组统计命中率,发现算法在不同条件下的表现差异 | 分组命中率统计 | 中 |
|
||
|
||
**NDCG@K 实现:**
|
||
|
||
```php
|
||
/**
|
||
* 计算NDCG@K指标
|
||
* @param array $backtestDetails 回测详情
|
||
* @param int $K Top-K参数
|
||
* @return float NDCG值(0-1)
|
||
*/
|
||
private function _calculateNDCG($backtestDetails, $K = 5)
|
||
{
|
||
$dcg = 0;
|
||
$idcg = 0;
|
||
|
||
foreach ($backtestDetails as $detail) {
|
||
if ($detail['hit']) {
|
||
$rank = $detail['rank'];
|
||
if ($rank <= $K) {
|
||
// DCG: rel / log2(rank + 1),命中时rel=1
|
||
$dcg += 1 / log2($rank + 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
// IDCG: 最理想情况下所有命中的DCG(假设都排在第1位)
|
||
$hitCount = count(array_filter($backtestDetails, function($d) { return $d['hit']; }));
|
||
for ($i = 1; $i <= min($hitCount, $K); $i++) {
|
||
$idcg += 1 / log2($i + 1);
|
||
}
|
||
|
||
return $idcg > 0 ? round($dcg / $idcg, 4) : 0;
|
||
}
|
||
|
||
/**
|
||
* 计算MRR (Mean Reciprocal Rank)
|
||
* @param array $backtestDetails 回测详情
|
||
* @return float MRR值
|
||
*/
|
||
private function _calculateMRR($backtestDetails)
|
||
{
|
||
$reciprocalRanks = [];
|
||
|
||
foreach ($backtestDetails as $detail) {
|
||
if ($detail['hit']) {
|
||
$reciprocalRanks[] = 1 / $detail['rank'];
|
||
} else {
|
||
$reciprocalRanks[] = 0; // 未命中记为0
|
||
}
|
||
}
|
||
|
||
return count($reciprocalRanks) > 0
|
||
? round(array_sum($reciprocalRanks) / count($reciprocalRanks), 4)
|
||
: 0;
|
||
}
|
||
|
||
/**
|
||
* 计算命中率分布
|
||
* @param array $backtestDetails 回测详情
|
||
* @return array 各排名命中次数
|
||
*/
|
||
private function _calculateHitDistribution($backtestDetails)
|
||
{
|
||
$distribution = array_fill(1, 5, 0);
|
||
|
||
foreach ($backtestDetails as $detail) {
|
||
if ($detail['hit'] && $detail['rank'] >= 1 && $detail['rank'] <= 5) {
|
||
$distribution[$detail['rank']]++;
|
||
}
|
||
}
|
||
|
||
return $distribution;
|
||
}
|
||
```
|
||
|
||
**回测结果结构扩展:**
|
||
|
||
```php
|
||
// 在 _runBacktestV3 返回中添加新指标
|
||
return [
|
||
'hit_rate' => $hitRate,
|
||
'avg_rank' => $avgRank,
|
||
'total_tests' => $testCount,
|
||
'total_hits' => $hits,
|
||
'details' => $details,
|
||
// 新增指标
|
||
'ndcg_5' => $this->_calculateNDCG($details, 5),
|
||
'mrr' => $this->_calculateMRR($details),
|
||
'hit_distribution' => $this->_calculateHitDistribution($details),
|
||
'precision_5' => round($hits / ($testCount * 5) * 100, 2) // Precision@5
|
||
];
|
||
```
|
||
|
||
**置信度:** HIGH [CITED: 推荐系统评估指标最佳实践] - NDCG、MRR、MAP是成熟的排名质量评估指标
|
||
|
||
---
|
||
|
||
### 方向6: 组合特征挖掘
|
||
|
||
**目标:** 发现更复杂的号码组合规律,提升组合特征维度的预测能力
|
||
|
||
**推荐挖掘方法:**
|
||
|
||
| 方法 | 技术细节 | 实现复杂度 | 适用场景 |
|
||
|------|----------|------------|----------|
|
||
| **关联规则挖掘(Apriori)** | 发现号码组合的频繁共现模式,如"号码A出现时号码B也出现" | 中 | 双号码组合发现 |
|
||
| **序列模式挖掘** | 发现连续N期的号码序列模式,如"连续3期单号后下期双号概率高" | 中 | 跨期规律发现 |
|
||
| **条件概率网络** | 构建号码属性的条件概率图,分析多属性联合影响 | 高 | 复杂条件依赖 |
|
||
| **多号码组合共现** | 统计3个以上号码的联合出现频率,发现"热门组合" | 中 | 组合投注建议 |
|
||
|
||
**关联规则挖掘实现思路:**
|
||
|
||
```php
|
||
/**
|
||
* Apriori关联规则挖掘
|
||
* @param array $history 历史数据(降序)
|
||
* @param float $minSupport 最小支持度阈值
|
||
* @param float $minConfidence 最小置信度阈值
|
||
* @return array 规则列表 [{antecedent: [], consequent: [], support: float, confidence: float}]
|
||
*/
|
||
private function _mineAssociationRules($history, $minSupport = 0.05, $minConfidence = 0.3)
|
||
{
|
||
// 简化实现:仅挖掘2项集规则(号码A -> 号码B)
|
||
// 完整Apriori需实现k项集迭代生成
|
||
|
||
$pairCounts = [];
|
||
$singleCounts = array_fill(1, 49, 0);
|
||
$totalPeriods = count($history);
|
||
|
||
// 统计单号码和号码对出现次数
|
||
foreach ($history as $row) {
|
||
$nums = $this->_extractAllNumbers($row); // 提取本期所有7个号码
|
||
foreach ($nums as $num) {
|
||
if ($num >= 1 && $num <= 49) {
|
||
$singleCounts[$num]++;
|
||
}
|
||
}
|
||
|
||
// 统计号码对(在同一期内共现)
|
||
for ($i = 0; $i < count($nums); $i++) {
|
||
for ($j = $i + 1; $j < count($nums); $j++) {
|
||
if ($nums[$i] >= 1 && $nums[$i] <= 49 && $nums[$j] >= 1 && $nums[$j] <= 49) {
|
||
$pairKey = min($nums[$i], $nums[$j]) . '-' . max($nums[$i], $nums[$j]);
|
||
$pairCounts[$pairKey] = ($pairCounts[$pairKey] ?? 0) + 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 生成规则
|
||
$rules = [];
|
||
foreach ($pairCounts as $pairKey => $pairCount) {
|
||
$support = $pairCount / $totalPeriods;
|
||
if ($support < $minSupport) continue;
|
||
|
||
$nums = explode('-', $pairKey);
|
||
$numA = (int)$nums[0];
|
||
$numB = (int)$nums[1];
|
||
|
||
// 规则: numA -> numB
|
||
$confidenceAB = $pairCount / $singleCounts[$numA];
|
||
if ($confidenceAB >= $minConfidence) {
|
||
$rules[] = [
|
||
'antecedent' => [$numA],
|
||
'consequent' => [$numB],
|
||
'support' => round($support, 4),
|
||
'confidence' => round($confidenceAB, 4)
|
||
];
|
||
}
|
||
|
||
// 规则: numB -> numA
|
||
$confidenceBA = $pairCount / $singleCounts[$numB];
|
||
if ($confidenceBA >= $minConfidence) {
|
||
$rules[] = [
|
||
'antecedent' => [$numB],
|
||
'consequent' => [$numA],
|
||
'support' => round($support, 4),
|
||
'confidence' => round($confidenceBA, 4)
|
||
];
|
||
}
|
||
}
|
||
|
||
// 按置信度排序
|
||
usort($rules, function($a, $b) {
|
||
return $b['confidence'] - $a['confidence'];
|
||
});
|
||
|
||
return $rules;
|
||
}
|
||
```
|
||
|
||
**序列模式挖掘实现思路:**
|
||
|
||
```php
|
||
/**
|
||
* 序列模式挖掘(连续N期特征模式)
|
||
* @param array $history 历史数据(降序)
|
||
* @param int $windowLength 序列窗口长度
|
||
* @return array 序列模式列表
|
||
*/
|
||
private function _mineSequencePatterns($history, $windowLength = 3)
|
||
{
|
||
$historyAsc = array_reverse($history);
|
||
$patterns = [];
|
||
|
||
// 构建特征序列
|
||
$featureSequence = [];
|
||
foreach ($historyAsc as $row) {
|
||
$num = (int)$row['num7'];
|
||
$featureSequence[] = [
|
||
'odd' => $num % 2 === 1,
|
||
'big' => $num >= 25,
|
||
'zone' => $this->_getZoneIdx($num)
|
||
];
|
||
}
|
||
|
||
// 统计窗口模式
|
||
$windowCounts = [];
|
||
for ($i = 0; $i < count($featureSequence) - $windowLength; $i++) {
|
||
$windowKey = '';
|
||
for ($j = 0; $j < $windowLength; $j++) {
|
||
$f = $featureSequence[$i + $j];
|
||
$windowKey .= ($f['odd'] ? 'O' : 'E') . ($f['big'] ? 'B' : 'S');
|
||
}
|
||
|
||
$nextFeature = $featureSequence[$i + $windowLength];
|
||
$nextKey = ($nextFeature['odd'] ? 'O' : 'E') . ($nextFeature['big'] ? 'B' : 'S');
|
||
|
||
$fullPattern = $windowKey . '->' . $nextKey;
|
||
$windowCounts[$fullPattern] = ($windowCounts[$fullPattern] ?? 0) + 1;
|
||
}
|
||
|
||
// 计算概率并返回高置信度模式
|
||
$totalPatterns = array_sum($windowCounts);
|
||
foreach ($windowCounts as $pattern => $count) {
|
||
$probability = $count / $totalPatterns;
|
||
if ($probability >= 0.1) { // 只返回概率>=10%的模式
|
||
$patterns[] = [
|
||
'pattern' => $pattern,
|
||
'count' => $count,
|
||
'probability' => round($probability, 4)
|
||
];
|
||
}
|
||
}
|
||
|
||
usort($patterns, function($a, $b) {
|
||
return $b['probability'] - $a['probability'];
|
||
});
|
||
|
||
return $patterns;
|
||
}
|
||
```
|
||
|
||
**注意事项:**
|
||
- 关联规则挖掘需要大量历史数据支撑(建议500期以上)
|
||
- 支持度和置信度阈值需根据数据量调整
|
||
- 挖掘结果需定期更新,避免过拟合特定时间段
|
||
- 可将挖掘结果缓存到文件或数据库,避免每次预测重复计算
|
||
|
||
**置信度:** MEDIUM [ASSUMED] - 关联规则挖掘是成熟的数据挖掘方法,但在彩票预测场景效果需验证
|
||
|
||
---
|
||
|
||
## Implementation Considerations
|
||
|
||
### 优先级排序
|
||
|
||
| 优先级 | 优化方向 | 理由 |
|
||
|--------|----------|------|
|
||
| P0 (高) | 置信度评估 | 用户决策辅助价值高,实现难度适中 |
|
||
| P0 (高) | 回测指标扩展 | 评估能力提升直接可见,实现难度低 |
|
||
| P1 (中) | 权重训练 | 提升算法准确性,需数据支撑 |
|
||
| P1 (中) | 转移概率增强 | 核心维度优化,预期收益较高 |
|
||
| P2 (低) | 组合特征挖掘 | 需大量数据,计算成本高 |
|
||
| P2 (低) | 数据维度扩展 | 需验证新维度有效性 |
|
||
|
||
### 实现风险
|
||
|
||
| 风险 | 影响 | 缓解措施 |
|
||
|------|------|----------|
|
||
| 过拟合历史数据 | 新数据表现下降 | 分时间段回测验证,权重定期重新优化 |
|
||
| 计算性能下降 | 预测响应变慢 | 预计算缓存、异步更新、降级策略 |
|
||
| 新维度效果不明显 | 权重稀释,整体命中率下降 | AB测试验证,无效维度移除 |
|
||
| 数据量不足 | 统计不可靠,置信度低 | 设置数据阈值,不足时提示用户 |
|
||
|
||
### 性能优化建议
|
||
|
||
1. **预计算缓存:** 将转移矩阵、组合特征统计等预计算结果缓存到文件或Redis
|
||
2. **批量计算:** 权重优化等耗时计算异步执行,结果存储供前端加载
|
||
3. **降级策略:** 数据不足时回退简化算法,避免不可靠预测
|
||
4. **增量更新:** 新开奖数据到达时增量更新统计,避免全量重算
|
||
|
||
### 数据需求
|
||
|
||
| 优化方向 | 最小数据量 | 推荐数据量 |
|
||
|----------|------------|------------|
|
||
| 基础预测 | 30期 | 200期 |
|
||
| 二阶马尔可夫 | 100期 | 500期 |
|
||
| 权重优化 | 200期 | 500期 |
|
||
| 关联规则挖掘 | 300期 | 500期+ |
|
||
| 置信度统计 | 50期回测 | 100期回测 |
|
||
|
||
---
|
||
|
||
## Validation Architecture
|
||
|
||
### Test Framework
|
||
|
||
| Property | Value |
|
||
|----------|-------|
|
||
| Framework | PHPUnit (ThinkPHP内置) |
|
||
| Config file | 无独立配置,通过 `php think unit` 运行 |
|
||
| Quick run command | `php think unit --filter HistoryTest` |
|
||
| Full suite command | `php think unit` |
|
||
|
||
### Phase Requirements → Test Map
|
||
|
||
| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|
||
|--------|----------|-----------|-------------------|-------------|
|
||
| PRED-01 | 置信度计算准确性 | unit | `php think unit --filter testConfidenceCalculation` | ❌ Wave 0 |
|
||
| PRED-02 | NDCG计算准确性 | unit | `php think unit --filter testNDCGCalculation` | ❌ Wave 0 |
|
||
| PRED-03 | 二阶马尔可夫转移矩阵构建 | unit | `php think unit --filter testTransitionMatrix2ndOrder` | ❌ Wave 0 |
|
||
| PRED-04 | 权重优化收敛性 | unit | `php think unit --filter testWeightOptimization` | ❌ Wave 0 |
|
||
| PRED-05 | 回测结果完整性 | unit | `php think unit --filter testBacktestV3Extended` | ❌ Wave 0 |
|
||
|
||
### Sampling Rate
|
||
|
||
- **Per task commit:** 快速单元测试覆盖核心方法
|
||
- **Per wave merge:** 回测验证使用真实历史数据
|
||
- **Phase gate:** 全量回测(100期)验证整体命中率提升
|
||
|
||
### Wave 0 Gaps
|
||
|
||
- [ ] `tests/HistoryTest.php` — 核心预测方法单元测试
|
||
- [ ] `tests/ConfidenceTest.php` — 置信度计算测试
|
||
- [ ] `tests/BacktestMetricsTest.php` — NDCG、MRR等指标计算测试
|
||
- [ ] 共享fixtures: 历史数据模拟生成器
|
||
|
||
---
|
||
|
||
## Security Domain
|
||
|
||
> 本阶段为算法优化,无用户输入处理、认证、数据持久化等安全敏感操作,security_enforcement 可设为 false。
|
||
|
||
### Applicable ASVS Categories
|
||
|
||
| ASVS Category | Applies | Standard Control |
|
||
|---------------|---------|-----------------|
|
||
| V2 Authentication | no | — |
|
||
| V3 Session Management | no | — |
|
||
| V4 Access Control | no | — |
|
||
| V5 Input Validation | no | — (权重参数由前端传入,需范围验证) |
|
||
| V6 Cryptography | no | — |
|
||
|
||
**权重参数验证建议:**
|
||
|
||
```php
|
||
// 在 getPredictionV3 中添加权重范围验证
|
||
foreach ($weights as $key => $value) {
|
||
if ($value < 0 || $value > 1) {
|
||
return ['predictions' => [], 'error' => '权重值必须在0-1之间'];
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Sources
|
||
|
||
### Primary (HIGH confidence)
|
||
- 现有代码分析: `application/admin/model/History.php` — getPredictionV3 及相关方法 [VERIFIED]
|
||
- 现有代码分析: `public/assets/js/backend/history.js` — showPredictDialog 及渲染逻辑 [VERIFIED]
|
||
|
||
### Secondary (MEDIUM confidence)
|
||
- 推荐系统评估指标: Hit Rate, NDCG, MRR, MAP [CITED: WebSearch Brave Search 结果]
|
||
- 参数优化方法: Grid Search, Genetic Algorithm [ASSUMED: 训练知识]
|
||
|
||
### Tertiary (LOW confidence)
|
||
- 马尔可夫链增强效果 [ASSUMED: 理论推导,需回测验证]
|
||
- 关联规则挖掘在彩票预测场景的效果 [ASSUMED: 需实际数据验证]
|
||
- 时间周期性特征有效性 [ASSUMED: 需历史数据分析验证]
|
||
|
||
---
|
||
|
||
## Assumptions Log
|
||
|
||
| # | Claim | Section | Risk if Wrong |
|
||
|---|-------|---------|---------------|
|
||
| A1 | 二阶马尔可夫链能提升转移概率预测准确性 | 方向2 | 预期收益下降,计算成本增加 |
|
||
| A2 | 网格搜索权重优化能提升命中率 | 方向3 | 优化无效或过拟合,需其他方法 |
|
||
| A3 | 置信度评估对用户决策有明显辅助价值 | 方向4 | 用户可能不理解置信度含义 |
|
||
| A4 | 时间周期性特征对号码分布有影响 | 方向1 | 新维度无效,权重稀释 |
|
||
| A5 | 关联规则挖掘能发现有效号码组合规律 | 方向6 | 挖掘结果不可靠,计算成本高 |
|
||
|
||
---
|
||
|
||
## Open Questions (RESOLVED)
|
||
|
||
1. **历史数据量是否足够支撑高级优化?**
|
||
- 当前默认200期统计,二阶马尔可夫和关联规则挖掘建议500期+
|
||
- 需检查数据库中实际可用的历史期数
|
||
- 推荐: 查询 `SELECT COUNT(*) FROM fa_history` 确认数据量
|
||
- **Resolution:** 11-05 Task 3 设置100期阈值,数据不足时回退一阶马尔可夫,已在plan中处理
|
||
|
||
2. **权重优化结果如何持久化?**
|
||
- 选项A: 存储到 `application/extra/predict.php` 配置文件
|
||
- 选项B: 存储到数据库配置表
|
||
- 选项C: 每次预测时动态计算(性能成本高)
|
||
- **Resolution:** 11-04 采用选项C(动态计算)+ 返回结果给前端展示,不持久化。设计决策:避免过拟合特定时间段,每次获取最新优化结果
|
||
|
||
3. **置信度阈值如何定义?**
|
||
- 当前假设: >=70%为高,50-70%为中,<50%为低
|
||
- 需根据实际回测数据调整阈值
|
||
- **Resolution:** 11-02 Task 1 明确阈值定义:>=70%高(绿色)、50-70%中(橙色)、<50%低(红色),前端11-03使用相同映射
|
||
|
||
4. **前端如何展示新增的回测指标(NDCG、MRR)?**
|
||
- 需设计用户友好的展示方式
|
||
- 可考虑简化为"预测质量评分"单一指标
|
||
- **Resolution:** 11-03 Task 2 实现百分比显示 + 柱状图:NDCG@5/MRR以百分比展示,命中分布以柱状图可视化
|
||
|
||
---
|
||
|
||
## Metadata
|
||
|
||
**Confidence breakdown:**
|
||
- 现有代码分析: HIGH — 直接阅读代码确认
|
||
- 回测指标扩展: HIGH — 基于成熟的推荐系统评估指标
|
||
- 置信度评估: MEDIUM — 实现方案可行,效果需验证
|
||
- 转移概率增强: MEDIUM — 理论可行,需回测验证效果
|
||
- 权重训练: MEDIUM — 方法成熟,但需足够数据支撑
|
||
- 组合特征挖掘: LOW — 需大量数据和验证
|
||
- 数据维度扩展: LOW — 新维度有效性不确定
|
||
|
||
**Research date:** 2026-05-01
|
||
**Valid until:** 30 days (算法优化方向相对稳定,但具体参数需定期验证) |