PHP项目分析赛季末斗志差异的方案
"赛季末斗志差异"通常出现在体育竞技、游戏对战、销售竞赛等场景,下面给出一个完整的 PHP 分析思路和实现方案。

明确业务定义
"斗志"是抽象概念,必须量化成可计算指标,常见代理指标:
| 维度 | 指标示例 |
|---|---|
| 出勤/参与 | 出战场次、活跃天数、签到率 |
| 投入度 | 平均时长、操作次数、任务完成率 |
| 胜负欲 | 关键时刻胜率、逆风翻盘次数、加时赛表现 |
| 稳定性 | 表现方差、连败后反弹率 |
| 赛季末特化 | 冲榜行为、最后一轮胜率、弃赛率 |
先和业务方对齐:赛季末 = N 轮/X 天,基准期 = 赛季中期。
数据模型设计
-- 赛季表
CREATE TABLE seasons (
id INT PRIMARY KEY,
name VARCHAR(50),
start_date DATE,
end_date DATE
);
-- 参赛者赛季记录
CREATE TABLE season_records (
id BIGINT PRIMARY KEY,
season_id INT,
player_id INT,
match_date DATE,
round_no INT, -- 第几轮
is_win TINYINT,
duration_sec INT, -- 出场时长
actions INT, -- 操作数/贡献值
quit TINYINT DEFAULT 0, -- 是否弃权
INDEX idx_season_player (season_id, player_id),
INDEX idx_date (match_date)
);
核心分析逻辑(PHP 实现)
划分阶段
class SeasonPhaseDivider
{
public function divide(array $season): array
{
$start = new DateTime($season['start_date']);
$end = new DateTime($season['end_date']);
$total = $start->diff($end)->days;
// 赛季末定义:20% 时间
$endPhaseStart = (clone $end)->modify('-' . (int)($total * 0.2) . ' days');
// 赛季中期:中间 40%
$midPhaseStart = (clone $start)->modify('+' . (int)($total * 0.3) . ' days');
$midPhaseEnd = (clone $start)->modify('+' . (int)($total * 0.7) . ' days');
return [
'end' => [$endPhaseStart->format('Y-m-d'), $end->format('Y-m-d')],
'mid' => [$midPhaseStart->format('Y-m-d'), $midPhaseEnd->format('Y-m-d')],
];
}
}
提取每人分阶段指标
class MoraleMetricsExtractor
{
public function __construct(private PDO $pdo) {}
public function extract(int $seasonId, string $from, string $to): array
{
$sql = "SELECT player_id,
COUNT(*) AS games,
SUM(is_win) AS wins,
AVG(duration_sec) AS avg_duration,
AVG(actions) AS avg_actions,
SUM(quit) / COUNT(*) AS quit_rate
FROM season_records
WHERE season_id = :sid AND match_date BETWEEN :from AND :to
GROUP BY player_id";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([':sid' => $seasonId, ':from' => $from, ':to' => $to]);
$rows = [];
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $r) {
$rows[$r['player_id']] = [
'games' => (int)$r['games'],
'win_rate' => $r['games'] ? $r['wins'] / $r['games'] : 0,
'avg_duration' => (float)$r['avg_duration'],
'avg_actions' => (float)$r['avg_actions'],
'quit_rate' => (float)$r['quit_rate'],
];
}
return $rows;
}
}
计算"斗志指数"(相对变化)
class MoraleDiffAnalyzer
{
// 各指标的权重,可按业务调
private array $weights = [
'win_rate' => 0.3,
'avg_actions' => 0.3,
'avg_duration' => 0.2,
'quit_rate' => -0.2, // 反向指标
];
public function analyze(array $mid, array $end): array
{
$result = [];
foreach ($end as $pid => $endMetrics) {
if (!isset($mid[$pid])) continue;
$score = 0.0;
$deltas = [];
foreach ($this->weights as $metric => $w) {
$m = $mid[$pid][$metric] ?? 0;
$e = $endMetrics[$metric] ?? 0;
// 相对变化,避免大数值指标主导
$delta = $m > 0 ? ($e - $m) / $m : ($e > 0 ? 1 : 0);
$delta = max(-1, min(1, $delta)); // 裁剪到 [-1,1]
$deltas[$metric] = round($delta, 4);
$score += $w * $delta;
}
$result[$pid] = [
'morale_score' => round($score * 100, 2), // 转成 -100~100
'deltas' => $deltas,
'trend' => $this->classify($score),
];
}
return $result;
}
private function classify(float $score): string
{
return match (true) {
$score > 0.15 => '冲刺型', // 末段发力
$score < -0.15 => '疲软型', // 末段掉链
default => '稳定型',
};
}
}
汇总与输出
$divider = new SeasonPhaseDivider(); $phases = $divider->divide($season); $extractor = new MoraleMetricsExtractor($pdo); $mid = $extractor->extract($season['id'], ...$phases['mid']); $end = $extractor->extract($season['id'], ...$phases['end']); $analyzer = new MoraleDiffAnalyzer(); $report = $analyzer->analyze($mid, $end); // 按士气分排序 uasort($report, fn($a, $b) => $b['morale_score'] <=> $a['morale_score']);
进阶分析方法
- 统计显著性检验:对胜负率做卡方 / t 检验,避免小样本误判(可引入
PHPStatistics或调 R/Python 微服务)。 - 时间序列趋势:用移动平均观察末段是否加速/放缓,而非仅比两段。
- 分组对比:按排名段(保级组 vs 争冠组)分组,斗志模式往往不同——保级区通常末段斗志最高。
- 控制变量:以"赛程强度/对手水平"为协变量回归,剔除强队对手造成的假性下滑。
- 可视化:输出雷达图(各指标 delta)+ 时间趋势折线,前端用 ECharts 展示。
工程注意事项
- 小样本保护:场次 < 5 的参赛者标记为"数据不足",不进入排名。
- 缓存结果:分析结果落
morale_analysis表,随赛季结束/每日批量重算,避免实时跑全表。 - 可配置权重:把
weights和"末段定义"放配置表,业务方可调,避免写死。 - 口径一致性:弃权、退赛如何处理需明确(作为负指标还是剔除)。
- 防作弊:刷操作数、故意弃赛等行为要单独规则识别。
推荐目录结构
app/
├── Service/
│ └── Morale/
│ ├── SeasonPhaseDivider.php
│ ├── MoraleMetricsExtractor.php
│ ├── MoraleDiffAnalyzer.php
│ └── ReportBuilder.php
├── Console/
│ └── AnalyzeMoraleCommand.php # php think/craft 批量任务
└── config/morale_weights.php
需要我针对你的具体场景(体育联赛 / 游戏排位 / 销售竞赛)细化指标和权重设计,或补上"统计显著性检验 + 可视化接口"的完整代码吗?告诉我你的数据源结构即可。