# 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 (算法优化方向相对稳定，但具体参数需定期验证)