From 663d83c25c271b6ce93c01feea602ce893aa00ba Mon Sep 17 00:00:00 2001 From: leon <916117771@qq.com> Date: Fri, 1 May 2026 15:13:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(11-02):=20=E5=AE=9E=E7=8E=B0=E9=A2=84?= =?UTF-8?q?=E6=B5=8B=E7=BD=AE=E4=BF=A1=E5=BA=A6=E8=AF=84=E4=BC=B0=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 _calculateConfidence 方法计算预测置信度 - 新增 _getHistoricalHitRateByRank 计算历史排名命中率 - 新增 _getScoreDistributionConfidence 计算得分分布置信度 - 新增 _getScoreConcentration 计算得分集中度 - 置信度三维度加权公式: 0.4*历史命中率 + 0.3*得分分布 + 0.3*集中度 - 数据量检查: 不足50期时返回警告 - getPredictionV3 返回结构新增 confidence 字段 --- application/admin/model/History.php | 181 +++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 1 deletion(-) diff --git a/application/admin/model/History.php b/application/admin/model/History.php index 4c32c8b..3c57cfa 100644 --- a/application/admin/model/History.php +++ b/application/admin/model/History.php @@ -2413,6 +2413,11 @@ class History extends Model // ====== 10. 历史回测验证 ====== $backtest = $skipBacktest ? null : $this->_runBacktestV3($periods, $weights, $backtestCount, $cutoffTime); + // ====== 11. 置信度评估(新增)====== + // 最小数据量阈值设为50期,不足时置信度基于估算 + $minDataThreshold = 50; + $confidence = $this->_calculateConfidence($predictions, $backtest, null, $minDataThreshold); + // 计算命中情况 $hitInfo = null; if ($actualResult) { @@ -2440,7 +2445,8 @@ class History extends Model 'analysis' => $analysis, 'actual_result' => $actualResult, 'hit_info' => $hitInfo, - 'backtest' => $backtest + 'backtest' => $backtest, + 'confidence' => $confidence // 新增置信度字段 ]; } @@ -3722,5 +3728,178 @@ class History extends Model return $distribution; } + /** + * 计算预测置信度 + * + * 置信度组成(三个维度加权平均): + * - 维度1: 历史排名命中率 (权重0.4) - 基于回测数据统计各排名位置的命中率 + * - 维度2: 得分分布置信度 (权重0.3) - 当前号码得分与Top5得分范围的比例关系 + * - 维度3: 得分集中度 (权重0.3) - Top5得分与平均得分的差距,差距越大置信度越高 + * + * 加权公式: + * confidence = 0.4 * historical_hit_rate + 0.3 * score_distribution + 0.3 * score_concentration + * + * 阈值定义: + * - 高置信度: >= 70% (绿色展示) + * - 中置信度: 50-70% (橙色展示) + * - 低置信度: < 50% (红色展示) + * + * @param array $predictions 预测结果数组(Top5) + * @param array $backtest 回测结果 + * @param array $scoresAll 所有号码得分详情(可选,用于集中度计算) + * @param int $minDataThreshold 最小数据量阈值,默认50期 + * @return array {confidence_scores: [], overall_confidence: float, data_warning: string|null} + */ + private function _calculateConfidence($predictions, $backtest, $scoresAll = null, $minDataThreshold = 50) + { + // 数据量检查 + $dataWarning = null; + $hasBacktest = $backtest && !empty($backtest['details']) && $backtest['total_tests'] > 0; + + if (!$hasBacktest || $backtest['total_tests'] < $minDataThreshold) { + $dataWarning = '回测数据不足(' . ($backtest['total_tests'] ?? 0) . '期),置信度基于估算,建议至少50期'; + } + + $confidenceScores = []; + + // 计算Top5平均得分(用于集中度计算) + $avgScore = 0; + if (!empty($predictions)) { + $totalScore = array_sum(array_column($predictions, 'score')); + $avgScore = $totalScore / count($predictions); + } + + foreach ($predictions as $idx => $pred) { + $rank = $idx + 1; + $num = $pred['num']; + $score = $pred['score']; + + // 维度1: 历史排名命中率 (权重0.4) + $rankHitRate = $this->_getHistoricalHitRateByRank($rank, $backtest); + + // 维度2: 得分分布置信度 (权重0.3) - 得分比例 + $scoreDistribution = $this->_getScoreDistributionConfidence($score, $predictions); + + // 维度3: 得分集中度 (权重0.3) - Top得分与平均得分的差距比例 + $scoreConcentration = $this->_getScoreConcentration($score, $avgScore, $predictions); + + // 综合置信度(加权平均) + $overallConfidence = $rankHitRate * 0.4 + $scoreDistribution * 0.3 + $scoreConcentration * 0.3; + + $confidenceScores[] = [ + 'num' => $num, + 'rank' => $rank, + 'confidence' => round($overallConfidence * 100, 1), + 'rank_hit_rate' => round($rankHitRate * 100, 1), + 'score_distribution' => round($scoreDistribution * 100, 1), + 'score_concentration' => round($scoreConcentration * 100, 1) + ]; + } + + // 整体置信度(Top5平均) + $overallConfidence = count($confidenceScores) > 0 + ? round(array_sum(array_column($confidenceScores, 'confidence')) / count($confidenceScores), 1) + : 0; + + return [ + 'confidence_scores' => $confidenceScores, + 'overall_confidence' => $overallConfidence, + 'data_warning' => $dataWarning + ]; + } + + /** + * 基于历史排名获取命中率 + * + * 计算方法: + * - 有回测数据时: 统计各排名的历史命中次数 / 总测试次数 + * - 无回测数据时: 根据排名估算,排名越靠前置信度越高 + * 估算公式: 1 - (rank - 1) * 0.15,即第1名估算85%,第5名估算25% + * + * @param int $rank 排名位置 (1-5) + * @param array $backtest 回测结果 + * @return float 该排名的历史命中率 (0-1) + */ + private function _getHistoricalHitRateByRank($rank, $backtest) + { + if (!$backtest || empty($backtest['details']) || $backtest['total_tests'] == 0) { + // 无回测数据时,根据排名估算(排名越靠前置信度越高) + // 估算公式: 1 - (rank - 1) * 0.15 + // 第1名: 1.0, 第2名: 0.85, 第3名: 0.70, 第4名: 0.55, 第5名: 0.40 + 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; + } + + /** + * 计算得分分布置信度 + * + * 计算方法: + * - 得分比例 = (score - bottomScore) / (topScore - bottomScore) + * - 得分越接近第一名,置信度越高 + * - 所有得分相同时返回1 + * + * @param float $score 当前号码得分 + * @param array $predictions 所有预测结果 + * @return float 得分置信度 (0-1) + */ + private function _getScoreDistributionConfidence($score, $predictions) + { + if (empty($predictions)) return 0; + + $topScore = $predictions[0]['score']; + $bottomScore = end($predictions)['score']; + + if ($topScore == $bottomScore) return 1; // 所有得分相同 + + // 得分比例:(score - bottom) / (top - bottom) + $ratio = ($score - $bottomScore) / ($topScore - $bottomScore); + return max(0, min(1, $ratio)); + } + + /** + * 计算得分集中度 + * + * 计算方法: + * - 集中度 = (score - avgScore) / (topScore - avgScore) 如果 score > avgScore + * - 集中度 = 0 如果 score <= avgScore + * - Top得分与平均得分差距越大,集中度越高,表示预测结果区分度明显 + * + * @param float $score 当前号码得分 + * @param float $avgScore Top5平均得分 + * @param array $predictions 所有预测结果 + * @return float 集中度置信度 (0-1) + */ + private function _getScoreConcentration($score, $avgScore, $predictions) + { + if (empty($predictions)) return 0; + + $topScore = $predictions[0]['score']; + + // 如果得分低于平均,集中度为0 + if ($score <= $avgScore) { + return 0; + } + + // 如果Top得分等于平均,所有得分相同,集中度为0.5 + if ($topScore == $avgScore) { + return $score == $topScore ? 0.5 : 0; + } + + // 集中度 = (score - avg) / (top - avg) + $concentration = ($score - $avgScore) / ($topScore - $avgScore); + return max(0, min(1, $concentration)); + } + }