From e61d98607f4770b734abf63813fb6d3faf201b51 Mon Sep 17 00:00:00 2001 From: leon <916117771@qq.com> Date: Fri, 1 May 2026 15:16:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(11-04):=20=E5=AE=9E=E7=8E=B0=E6=9D=83?= =?UTF-8?q?=E9=87=8D=E7=BD=91=E6=A0=BC=E6=90=9C=E7=B4=A2=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - History.php model 新增 _optimizeWeightsGridSearch 方法 - 5种预定义权重配置:遗漏优先型、转移概率优先型、走势方向优先型、平衡型、组合特征优先型 - 优化目标:综合得分 = hit_rate*0.6 + ndcg_5*100*0.4 - 超时保护机制:默认60秒,超时后停止剩余配置测试 - History.php controller 新增 optimizeWeights 接口入口 - 参数验证:periods(50-500)、backtest(10-100)、timeout(10-120) - 超时警告提示 --- application/admin/controller/History.php | 149 ++++++++++++++++++++- application/admin/model/History.php | 158 +++++++++++++++++++++++ 2 files changed, 306 insertions(+), 1 deletion(-) diff --git a/application/admin/controller/History.php b/application/admin/controller/History.php index bca15bf..8044dec 100644 --- a/application/admin/controller/History.php +++ b/application/admin/controller/History.php @@ -22,7 +22,7 @@ class History extends Backend * 无需额外权限检查的方法(但仍在 admin 模块内,需要 admin 登录) * @var array */ - protected $noNeedRight = ['missingNum', 'trendData', 'hotColdNumbers', 'colorWaveAnalysis', 'zodiacAnalysis', 'oddEvenAnalysis', 'bigSmallAnalysis', 'specialTrend', 'consecutiveNumbers', 'tailNumbers', 'dashboard', 'specialHeatmap', 'specialHotColdAction', 'zoneTransition', 'colorWaveTransition', 'zoneToColorTransition', 'zodiacTransition', 'tailNumberTransition', 'headNumberTransition']; + protected $noNeedRight = ['missingNum', 'trendData', 'hotColdNumbers', 'colorWaveAnalysis', 'zodiacAnalysis', 'oddEvenAnalysis', 'bigSmallAnalysis', 'specialTrend', 'consecutiveNumbers', 'tailNumbers', 'dashboard', 'specialHeatmap', 'specialHotColdAction', 'zoneTransition', 'colorWaveTransition', 'zoneToColorTransition', 'zodiacTransition', 'tailNumberTransition', 'headNumberTransition', 'predict', 'predictV2', 'predictV3', 'optimizeWeights']; public function _initialize() { @@ -388,5 +388,152 @@ class History extends Backend } } + /** + * 综合预测号码 + * 基于历史多维度转移概率分析,给出号码预测建议 + */ + public function predict() + { + if ($this->request->isAjax()) { + $periods = $this->request->get('periods', 100, 'intval'); + if ($periods < 10 || $periods > 500) { + $this->error('期数范围必须在 10-500 之间'); + } + // 权重配置(可选) + $weights = []; + $weightStr = $this->request->get('weights', '', 'trim'); + if ($weightStr) { + $weightsArr = json_decode($weightStr, true); + if (is_array($weightsArr)) { + $weights = $weightsArr; + } + } + // 目标期号(可选,用于验证历史预测成功率) + $targetExpect = $this->request->get('target_expect', '', 'trim'); + $result = $this->model->getPrediction($periods, $weights, $targetExpect); + if (isset($result['error'])) { + $this->error($result['error']); + } + $this->success('查询成功', null, $result); + } + } + + /** + * 改进版智能预测算法 + * 基于统计回归分析,包含遗漏回归、频率回归、区域平衡等多维度评分 + */ + public function predictV2() + { + if ($this->request->isAjax()) { + $periods = $this->request->get('periods', 200, 'intval'); + if ($periods < 30 || $periods > 500) { + $this->error('期数范围必须在 30-500 之间'); + } + // 权重配置(可选) + $weights = []; + $weightStr = $this->request->get('weights', '', 'trim'); + if ($weightStr) { + $weightsArr = json_decode($weightStr, true); + if (is_array($weightsArr)) { + $weights = $weightsArr; + } + } + // 目标期号(可选,用于验证历史预测成功率) + $targetExpect = $this->request->get('target_expect', '', 'trim'); + // 回测期数(可选) + $backtestCount = $this->request->get('backtest', 50, 'intval'); + if ($backtestCount < 10 || $backtestCount > 100) { + $backtestCount = 50; + } + $result = $this->model->getPredictionV2($periods, $weights, $targetExpect, false, $backtestCount); + if (isset($result['error'])) { + $this->error($result['error']); + } + $this->success('查询成功', null, $result); + } + } + + /** + * 多维度综合预测算法 V3 + * 新增维度:转移概率(马尔可夫链)、单双规律、大小规律、走势方向分析 + */ + public function predictV3() + { + if ($this->request->isAjax()) { + $periods = $this->request->get('periods', 200, 'intval'); + if ($periods < 30 || $periods > 500) { + $this->error('期数范围必须在 30-500 之间'); + } + // 权重配置(可选) + $weights = []; + $weightStr = $this->request->get('weights', '', 'trim'); + if ($weightStr) { + $weightsArr = json_decode($weightStr, true); + if (is_array($weightsArr)) { + $weights = $weightsArr; + } + } + // 目标期号(可选,用于验证历史预测成功率) + $targetExpect = $this->request->get('target_expect', '', 'trim'); + // 回测期数(可选) + $backtestCount = $this->request->get('backtest', 50, 'intval'); + if ($backtestCount < 10 || $backtestCount > 100) { + $backtestCount = 50; + } + $result = $this->model->getPredictionV3($periods, $weights, $targetExpect, false, $backtestCount); + if (isset($result['error'])) { + $this->error($result['error']); + } + $this->success('查询成功', null, $result); + } + } + + /** + * 权重网格搜索优化接口 + * 执行多权重配置回测,返回最优权重组合 + * + * 参数说明: + * - periods: 统计期数,范围50-500,默认200 + * - backtest: 回测期数,范围10-100,默认30 + * - timeout: 超时秒数,范围10-120,默认60 + * + * 返回说明: + * - best_weights: 最优权重配置 + * - best_hit_rate: 最优配置命中率 + * - all_results: 所有配置测试结果 + * - timed_out: 是否超时中断 + */ + public function optimizeWeights() + { + if ($this->request->isAjax()) { + // 参数验证 + $periods = $this->request->get('periods', 200, 'intval'); + if ($periods < 50 || $periods > 500) { + $this->error('期数范围必须在 50-500 之间'); + } + + $backtestCount = $this->request->get('backtest', 30, 'intval'); + if ($backtestCount < 10 || $backtestCount > 100) { + $backtestCount = 30; // 使用默认值而非报错 + } + + $timeoutSeconds = $this->request->get('timeout', 60, 'intval'); + if ($timeoutSeconds < 10 || $timeoutSeconds > 120) { + $timeoutSeconds = 60; // 使用默认值 + } + + // 执行优化 + $result = $this->model->_optimizeWeightsGridSearch($periods, $backtestCount, $timeoutSeconds); + + // 超时警告提示 + $message = '优化完成'; + if ($result['timed_out']) { + $message = '优化超时中断,已完成' . count($result['all_results']) . '种配置测试'; + } + + $this->success($message, null, $result); + } + } + } diff --git a/application/admin/model/History.php b/application/admin/model/History.php index 3c57cfa..a964487 100644 --- a/application/admin/model/History.php +++ b/application/admin/model/History.php @@ -3901,5 +3901,163 @@ class History extends Model return max(0, min(1, $concentration)); } + /** + * 权重网格搜索优化 + * + * 优化目标定义: + * - 综合评估得分 = hit_rate * 0.6 + ndcg_5 * 100 * 0.4 + * - 命中率权重60%,NDCG权重40% + * - 返回综合得分最高的权重配置 + * + * 5种预定义权重配置: + * - 配置1: 遗漏优先型 - omit_regression权重最高(0.25) + * - 配置2: 转移概率优先型 - transition_prob权重最高(0.25) + * - 配置3: 走势方向优先型 - trend_direction权重最高(0.25) + * - 配置4: 平衡型 - 各维度权重较均衡 + * - 配置5: 组合特征优先型 - combination权重最高(0.20) + * + * @param int $periods 统计期数,范围50-500 + * @param int $backtestCount 回测期数,范围10-100 + * @param int $timeoutSeconds 超时限制秒数,默认60秒 + * @return array {best_weights: [], best_hit_rate: float, best_ndcg: float, all_results: [], timed_out: bool} + */ + private function _optimizeWeightsGridSearch($periods = 200, $backtestCount = 50, $timeoutSeconds = 60) + { + // 超时保护:记录开始时间 + $startTime = microtime(true); + $timedOut = false; + + // 5种预定义权重配置(具体权重值明确) + $weightConfigs = [ + // 配置1: 遗漏优先型 - 遗漏回归权重最高 + [ + 'omit_regression' => 0.25, // 遗漏回归权重25% + 'freq_regression' => 0.12, // 频率回归权重12% + 'transition_prob' => 0.15, // 转移概率权重15% + 'trend_direction' => 0.12, // 走势方向权重12% + 'oddeven_balance' => 0.08, // 单双平衡权重8% + 'bigsmall_balance' => 0.08, // 大小平衡权重8% + 'zone_balance' => 0.05, // 区域平衡权重5% + 'color_balance' => 0.05, // 波色平衡权重5% + 'combination' => 0.10 // 组合特征权重10% + ], + // 配置2: 转移概率优先型 - 转移概率权重最高 + [ + 'omit_regression' => 0.15, + 'freq_regression' => 0.10, + 'transition_prob' => 0.25, // 转移概率权重25%(最高) + 'trend_direction' => 0.12, + 'oddeven_balance' => 0.08, + 'bigsmall_balance' => 0.08, + 'zone_balance' => 0.04, + 'color_balance' => 0.04, + 'combination' => 0.14 + ], + // 配置3: 走势方向优先型 - 走势方向权重最高 + [ + 'omit_regression' => 0.12, + 'freq_regression' => 0.10, + 'transition_prob' => 0.15, + 'trend_direction' => 0.25, // 走势方向权重25%(最高) + 'oddeven_balance' => 0.08, + 'bigsmall_balance' => 0.08, + 'zone_balance' => 0.04, + 'color_balance' => 0.04, + 'combination' => 0.12 + ], + // 配置4: 平衡型(默认配置)- 各维度权重较均衡 + [ + 'omit_regression' => 0.18, + 'freq_regression' => 0.12, + 'transition_prob' => 0.18, + 'trend_direction' => 0.14, + 'oddeven_balance' => 0.08, + 'bigsmall_balance' => 0.08, + 'zone_balance' => 0.04, + 'color_balance' => 0.04, + 'combination' => 0.10 + ], + // 配置5: 组合特征优先型 - 组合特征权重最高 + [ + 'omit_regression' => 0.15, + 'freq_regression' => 0.10, + 'transition_prob' => 0.15, + 'trend_direction' => 0.12, + 'oddeven_balance' => 0.06, + 'bigsmall_balance' => 0.06, + 'zone_balance' => 0.03, + 'color_balance' => 0.03, + 'combination' => 0.20 // 组合特征权重20%(最高) + ] + ]; + + $bestWeights = []; + $bestHitRate = 0; + $bestNdcg = 0; + $bestCombinedScore = 0; + $allResults = []; + + // 执行每种配置的回测(添加超时检查) + foreach ($weightConfigs as $configIdx => $weights) { + // 超时检查:超过限制时间则停止 + $elapsedTime = microtime(true) - $startTime; + if ($elapsedTime > $timeoutSeconds) { + $timedOut = true; + break; + } + + // 执行回测 + $backtest = $this->_runBacktestV3($periods, $weights, $backtestCount); + + $hitRate = $backtest['hit_rate'] ?? 0; + $ndcg = $backtest['ndcg_5'] ?? 0; + $avgRank = $backtest['avg_rank'] ?? 0; + $mrr = $backtest['mrr'] ?? 0; + + // 综合评估得分:命中率60% + NDCG40% + $combinedScore = $hitRate * 0.6 + $ndcg * 100 * 0.4; + + $result = [ + 'config_name' => $configIdx + 1, + 'config_type' => ['遗漏优先型', '转移概率优先型', '走势方向优先型', '平衡型', '组合特征优先型'][$configIdx], + 'weights' => $weights, + 'hit_rate' => $hitRate, + 'avg_rank' => $avgRank, + 'ndcg_5' => $ndcg, + 'mrr' => $mrr, + 'combined_score' => round($combinedScore, 2), + 'total_hits' => $backtest['total_hits'] ?? 0 + ]; + + $allResults[] = $result; + + // 更新最优配置 + if ($combinedScore > $bestCombinedScore) { + $bestCombinedScore = $combinedScore; + $bestHitRate = $hitRate; + $bestNdcg = $ndcg; + $bestWeights = $weights; + } + } + + // 按综合得分降序排序结果 + usort($allResults, function($a, $b) { + return $b['combined_score'] - $a['combined_score']; + }); + + return [ + 'best_weights' => $bestWeights, + 'best_hit_rate' => $bestHitRate, + 'best_ndcg' => $bestNdcg, + 'best_combined_score' => round($bestCombinedScore, 2), + 'all_results' => $allResults, + 'periods' => $periods, + 'backtest_count' => $backtestCount, + 'timeout_seconds' => $timeoutSeconds, + 'timed_out' => $timedOut, + 'elapsed_time' => round(microtime(true) - $startTime, 2) + ]; + } + }