综合php项目,中卫组合默契度如何量化?

wen PHP项目 2

中卫组合默契度量化框架(PHP 项目实践)

注:“中卫”我理解为中后卫(Center Back, CB)组合,若你指的是别的含义(如中场中路),可以再说明。

综合php项目,中卫组合默契度如何量化?

下面给出一套可落到 PHP 后端、可用于计算和存储的量化模型 + 数据结构 + 代码示例。


默契度的量化拆解

中卫默契度不是一个单一指标,建议拆成 4 个维度,加权求和 → 0~100 分。

维度 含义 数据来源 权重建议
D1 同场时长 两人共同出场时间(分钟) 比赛阵容事件 25%
D2 稳定性 同场时段的连续性(首发搭配占比) 首发/换人记录 20%
D3 防守协同 同场时的失球率、零封率、被射门数 比赛统计 35%
D4 行为互补 抢断/拦截/争顶/解围的互补性 球员事件统计 20%
默契度 = 0.25*D1 + 0.20*D2 + 0.35*D3 + 0.20*D4

各维度公式

D1 同场时长(归一化)

minutes_together = Σ 两人同场分钟
D1 = min(100, 100 * minutes_together / T_ref)   // T_ref 建议 = 900 分钟(10 场)

D2 稳定性

starts_together   = 两人同时首发的场次
matches_together  = 两人同场的场次
D2 = 100 * starts_together / max(1, matches_together)

D3 防守协同(对比基线,防止把“弱队失球多”算成不默契)

goals_conceded_together = 同场失球数
minutes_together
GA90 = goals_conceded_together / minutes_together * 90
baseline_GA90 = 该队整体 GA90(同赛季)
D3 = 100 * clamp(1 - (GA90 - baseline_GA90) / baseline_GA90, -1, 1)
   → 映射到 [0,100]

可选增强:把零封率作为另一子项,D3 = 0.6*GA90_score + 0.4*cleanSheet_score。

D4 行为互补性

对每人统计:抢断 T、拦截 I、争顶成功 H、解围 C。

互补度 = 1 - |x1 - x2| / (x1 + x2 + ε)      // 每项 0~1,越接近 1 越互补
D4 = 100 * mean(互补度_T, 互补度_I, 互补度_H, 互补度_C)

逻辑:两人风格过于重合(都是争顶型/都是拦截型)在高端局里协同性反而下降;一高一快、一抢一护的搭配通常更默契。


PHP 数据结构

final class CbPairMatchStat {
    public function __construct(
        public int $matchId,
        public int $playerA,
        public int $playerB,
        public int $minutesTogether,
        public bool $bothStarted,
        public int $goalsConceded,
        public int $cleanSheet,        // 0/1
        public array $statsA,          // ['tackle'=>, 'intercept'=>, 'aerial'=>, 'clear'=>]
        public array $statsB,
    ) {}
}

表建议:

CREATE TABLE cb_pair_match (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  match_id INT, player_a INT, player_b INT,
  minutes_together SMALLINT, both_started TINYINT,
  goals_conceded SMALLINT, clean_sheet TINYINT,
  tackle_a SMALLINT, tackle_b SMALLINT,
  intercept_a SMALLINT, intercept_b SMALLINT,
  aerial_a SMALLINT, aerial_b SMALLINT,
  clear_a SMALLINT, clear_b SMALLINT,
  UNIQUE KEY uq (match_id, player_a, player_b)
);

PHP 计算示例

final class CbSynergyCalculator
{
    public const W = ['d1'=>0.25, 'd2'=>0.20, 'd3'=>0.35, 'd4'=>0.20];
    public const T_REF = 900.0;
    /**
     * @param CbPairMatchStat[] $rows
     * @param float $teamGA90 球队赛季整体 GA90(基线)
     */
    public function compute(array $rows, float $teamGA90): array
    {
        $minutes = 0; $matches = 0; $starts = 0;
        $gc = 0; $cs = 0;
        $sum = ['tackle_a'=>0,'tackle_b'=>0,'intercept_a'=>0,'intercept_b'=>0,
                'aerial_a'=>0,'aerial_b'=>0,'clear_a'=>0,'clear_b'=>0];
        foreach ($rows as $r) {
            $minutes += $r->minutesTogether;
            $matches++;
            $starts += $r->bothStarted ? 1 : 0;
            $gc      += $r->goalsConceded;
            $cs      += $r->cleanSheet;
            foreach ($sum as $k => $_) {
                $sum[$k] += $r->statsA[explode('_', $k)[0]] ?? 0;
            }
        }
        // 修正:上面循环写法略繁琐,下面显式计算
        // D1
        $d1 = min(100.0, 100.0 * $minutes / self::T_REF);
        // D2
        $d2 = 100.0 * $starts / max(1, $matches);
        // D3
        $ga90 = $minutes > 0 ? $gc / $minutes * 90.0 : $teamGA90;
        $base = max($teamGA90, 0.1);
        $raw  = 1.0 - ($ga90 - $base) / $base;       // >0 好于基线,<0 差于基线
        $d3   = 100.0 * (max(-1.0, min(1.0, $raw)) + 1.0) / 2.0; // 映射到 0~100
        // D4
        $pairs = [
            [$sum['tackle_a'], $sum['tackle_b']],
            [$sum['intercept_a'], $sum['intercept_b']],
            [$sum['aerial_a'], $sum['aerial_b']],
            [$sum['clear_a'], $sum['clear_b']],
        ];
        $comp = 0.0;
        foreach ($pairs as [$x, $y]) {
            $comp += 1.0 - abs($x - $y) / ($x + $y + 1e-6);
        }
        $d4 = 100.0 * $comp / count($pairs);
        $score = self::W['d1']*$d1 + self::W['d2']*$d2
               + self::W['d3']*$d3 + self::W['d4']*$d4;
        return [
            'score' => round($score, 2),
            'd1' => round($d1,2), 'd2' => round($d2,2),
            'd3' => round($d3,2), 'd4' => round($d4,2),
            'minutes' => $minutes, 'matches' => $matches,
            'ga90' => round($ga90,2), 'baseline_ga90' => round($base,2),
        ];
    }
}

✅ 上面代码里第一个 foreach 那段我保留了一次示意,正式使用时删除,用下面的显式字段累加。


工程化落地要点

  1. 数据最小样本门槛:minutes_together < 180 时不输出默契度,标记为 “样本不足”,避免小样本噪声。
  2. 时间衰减:近 1 年权重高,可对每行加 exp(-Δdays/365) 权重,再用加权平均重算 D1~D4。
  3. 对手强度修正:D3 可用对手进攻强度(对手 xG/场)做基线调整,避免“只对弱队一起踢”被高估。
  4. 持久化 + 缓存:结果表 cb_pair_score(pair_key, score, d1..d4, sample, updated_at),pair_key = min(id_a,id_b).'-'.max(...),供前端/API 直接读。
  5. 增量更新:每场比赛结束后只重算涉及的组合(一个球员最多 3~5 个搭档),O(1) 更新即可。
  6. 可视化:雷达图 / 组合热力图(球员 × 球员矩阵),前端直接跑。

可扩展(进阶)

  • 用 xG prevented 替代失球数,噪声更小、样本效率更高。
  • 引入 空间覆盖互补(球员平均位置散点图的距离/重叠面积)——需要 tracking 数据。
  • 把 D2 换成 共现稳定性指数(同场组合在球队所有中卫组合中的占比 + 连续出场 run length)。
  • 做 贝叶斯收缩:小样本向球队均值收缩,score_shrunk = (n*score + k*prior) / (n + k)。

需要我把这套改成你现有 PHP 项目的表结构 / 框架(Laravel / Symfony / ThinkPHP)风格,或者补一个 API 返回结构 + 单元测试,告诉我用的框架和现有数据字段即可。

上一篇综合实时php项目,中场休息会如何调整?

下一篇当前分类已是最新一篇

抱歉,评论功能暂时关闭!

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝