feat(11-02): 实现预测置信度评估功能
- 新增 _calculateConfidence 方法计算预测置信度 - 新增 _getHistoricalHitRateByRank 计算历史排名命中率 - 新增 _getScoreDistributionConfidence 计算得分分布置信度 - 新增 _getScoreConcentration 计算得分集中度 - 置信度三维度加权公式: 0.4*历史命中率 + 0.3*得分分布 + 0.3*集中度 - 数据量检查: 不足50期时返回警告 - getPredictionV3 返回结构新增 confidence 字段
This commit is contained in:
@@ -2413,6 +2413,11 @@ class History extends Model
|
|||||||
// ====== 10. 历史回测验证 ======
|
// ====== 10. 历史回测验证 ======
|
||||||
$backtest = $skipBacktest ? null : $this->_runBacktestV3($periods, $weights, $backtestCount, $cutoffTime);
|
$backtest = $skipBacktest ? null : $this->_runBacktestV3($periods, $weights, $backtestCount, $cutoffTime);
|
||||||
|
|
||||||
|
// ====== 11. 置信度评估(新增)======
|
||||||
|
// 最小数据量阈值设为50期,不足时置信度基于估算
|
||||||
|
$minDataThreshold = 50;
|
||||||
|
$confidence = $this->_calculateConfidence($predictions, $backtest, null, $minDataThreshold);
|
||||||
|
|
||||||
// 计算命中情况
|
// 计算命中情况
|
||||||
$hitInfo = null;
|
$hitInfo = null;
|
||||||
if ($actualResult) {
|
if ($actualResult) {
|
||||||
@@ -2440,7 +2445,8 @@ class History extends Model
|
|||||||
'analysis' => $analysis,
|
'analysis' => $analysis,
|
||||||
'actual_result' => $actualResult,
|
'actual_result' => $actualResult,
|
||||||
'hit_info' => $hitInfo,
|
'hit_info' => $hitInfo,
|
||||||
'backtest' => $backtest
|
'backtest' => $backtest,
|
||||||
|
'confidence' => $confidence // 新增置信度字段
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3722,5 +3728,178 @@ class History extends Model
|
|||||||
return $distribution;
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user