feat(11-04): 实现权重网格搜索优化功能
- 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) - 超时警告提示
This commit is contained in:
@@ -22,7 +22,7 @@ class History extends Backend
|
|||||||
* 无需额外权限检查的方法(但仍在 admin 模块内,需要 admin 登录)
|
* 无需额外权限检查的方法(但仍在 admin 模块内,需要 admin 登录)
|
||||||
* @var array
|
* @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()
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3901,5 +3901,163 @@ class History extends Model
|
|||||||
return max(0, min(1, $concentration));
|
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)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user