中卫组合默契度量化方案(PHP 项目)
在足球数据分析中,中后卫组合的"默契度"是难以直接测量的隐性指标,下面给出一个可落地的 PHP 量化方案,核心思路是用可观测数据间接刻画默契,并输出 0–100 的默契分。

量化维度设计
默契度不能靠单一指标,建议从 4 个维度加权:
| 维度 | 含义 | 可观测代理指标 |
|---|---|---|
| 协同稳定性 | 两人同时出场且配合不出错的频率 | 同场时长占比、共同出场时失球率 |
| 空间互补性 | 覆盖区域是否互补而非重叠 | 防守热区重叠度、拦截/解围区域分布 |
| 行为同步性 | 防守动作的时序协同 | 同场时被反击次数、造越位成功率、协防补位次数 |
| 结果有效性 | 组合带来的实际防守产出 | 同场零封率、对方 xG 抑制、对抗成功率 |
数据模型(MySQL 表设计)
-- 球员基础
CREATE TABLE players (
id INT PRIMARY KEY,
name VARCHAR(50),
position VARCHAR(10) -- 'CB'
);
-- 比赛出场记录(每场每球员一条)
CREATE TABLE appearances (
id INT PRIMARY KEY,
match_id INT,
player_id INT,
minutes INT,
position VARCHAR(10),
goals_conceded INT, -- 该球员在场时丢球
xg_conceded DECIMAL(5,2),-- 该球员在场时对方 xG
interceptions INT,
clearances INT,
tackles_won INT,
duels_won INT,
offside_traps_success INT,
zone_grid VARCHAR(500) -- 防守热区网格 JSON,如 {"A1":12,"B2":8}
);
-- 比赛元数据
CREATE TABLE matches (
id INT PRIMARY KEY,
team_id INT,
opponent_id INT,
match_date DATE,
goals_conceded_total INT,
clean_sheet TINYINT
);
核心算法(PHP 实现)
找出"中卫组合"并统计同场数据
function getPairStats(PDO $pdo, int $cbA, int $cbB): array
{
// 找出两人同时出场(均为中卫且时间重叠)的比赛
$sql = "
SELECT a.match_id, m.clean_sheet, m.goals_conceded_total,
LEAST(a.minutes, b.minutes) AS shared_minutes,
a.xg_conceded AS xg_a, b.xg_conceded AS xg_b,
a.interceptions AS int_a, b.interceptions AS int_b,
a.clearances AS clr_a, b.clearances AS clr_b,
a.duels_won AS dw_a, b.duels_won AS dw_b,
a.zone_grid AS zone_a, b.zone_grid AS zone_b,
a.offside_traps_success AS trap_a,
b.offside_traps_success AS trap_b
FROM appearances a
JOIN appearances b ON a.match_id = b.match_id
JOIN matches m ON m.id = a.match_id
WHERE a.player_id = :a AND b.player_id = :b
AND a.position = 'CB' AND b.position = 'CB'
AND a.minutes > 0 AND b.minutes > 0
";
$stmt = $pdo->prepare($sql);
$stmt->execute([':a' => $cbA, ':b' => $cbB]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
四个子分数计算
function computeScores(array $rows): array
{
if (count($rows) === 0) {
return ['stability'=>0,'complement'=>0,'sync'=>0,'outcome'=>0];
}
$n = count($rows);
$sharedTotal = 0; $zeroSheet = 0;
$goalsPer90 = []; $xgPer90 = [];
$overlapSum = 0; $trapRate = []; $duelRate = [];
foreach ($rows as $r) {
$sharedTotal += $r['shared_minutes'];
if ($r['clean_sheet']) $zeroSheet++;
// 结果有效性:每 90 分钟丢球 & 对方 xG
if ($r['shared_minutes'] > 0) {
$goalsPer90[] = $r['goals_conceded_total'] * 90 / $r['shared_minutes'];
$xgPer90[] = (($r['xg_a'] + $r['xg_b']) / 2) * 90 / $r['shared_minutes'];
}
// 空间互补性:热区重叠度(Jaccard 相似度的补值)
$za = json_decode($r['zone_a'], true) ?: [];
$zb = json_decode($r['zone_b'], true) ?: [];
$overlapSum += 1 - jaccard(array_keys($za), array_keys($zb));
// 行为同步性:造越位成功率(两人合计)
$trapOps = max(1, $r['trap_a'] + $r['trap_b']);
$trapRate[] = $r['trap_a'] + $r['trap_b'];
// 对抗成功率
$duelOps = max(1, $r['dw_a'] + $r['dw_b']);
$duelRate[] = ($r['dw_a'] + $r['dw_b']) / $duelOps;
}
// 1) 协同稳定性:同场场次越多 + 零封率越高越稳
$stability = min(1, $n / 15) * 0.5 + ($zeroSheet / $n) * 0.5;
// 2) 空间互补性:重叠度越低(互补)越好
$complement = 1 - ($overlapSum / $n);
// 3) 行为同步性:造越位 + 对抗,归一化
$syncRaw = array_sum($trapRate) / $n; // 平均每场造越位数
$sync = min(1, $syncRaw / 4) * 0.5
+ (array_sum($duelRate) / $n) * 0.5;
// 4) 结果有效性:丢球越少、xG 抑制越强越好
$avgG90 = array_sum($goalsPer90) / $n;
$avgXg90 = array_sum($xgPer90) / $n;
$outcome = max(0, 1 - ($avgG90 / 2)) * 0.5
+ max(0, 1 - ($avgXg90 / 2.5)) * 0.5;
return [
'stability' => round($stability, 4),
'complement' => round($complement, 4),
'sync' => round($sync, 4),
'outcome' => round($outcome, 4),
];
}
function jaccard(array $a, array $b): float
{
$a = array_unique($a); $b = array_unique($b);
$inter = count(array_intersect($a, $b));
$union = count(array_unique(array_merge($a, $b)));
return $union === 0 ? 0 : $inter / $union;
}
加权汇总为 0–100 默契分
function compatibilityScore(array $s): float
{
// 权重可调:结果与稳定性优先
$w = [
'stability' => 0.30,
'complement' => 0.20,
'sync' => 0.25,
'outcome' => 0.25,
];
$score = 0;
foreach ($w as $k => $weight) {
$score += $s[$k] * $weight;
}
return round($score * 100, 2);
}
调用示例
$rows = getPairStats($pdo, 101, 102); // 两名中卫
$sub = computeScores($rows);
$final = compatibilityScore($sub);
echo "默契度总分:{$final}\n";
print_r($sub);
// 输出示例:
// 默契度总分:78.4
// ['stability'=>0.80,'complement'=>0.72,'sync'=>0.65,'outcome'=>0.85]
关键设计要点
- 共同出场时长是分母基准:所有比率都用
shared_minutes归一化,避免"同场 10 分钟"污染样本。 - 空间热区需预先网格化:把半场划分为 N×M 网格(如 6×4),统计每次防守事件落在哪个格子,才能算重叠度。
- 样本量惩罚:
min(1, n/15)确保组合出场 < 15 场时稳定性自动打折,防止小样本高估。 - 权重可配置:建议做成数据库配置表 or 配置文件,方便按联赛/战术风格调参。
- 归因修正(进阶):
xg_conceded应取"该中卫在场期间的对方 xG",而非全场,避免替补时段干扰。
可扩展方向
- 时序同步:若有事件级数据(时间戳),可用"两人防守动作时间差"衡量真正同步性(如 2 秒内补位)。
- 对手强度加权:按对手进攻强度对每场加权,避免"虐菜组合"虚高。
- 机器学习校准:用历史零封/失球作为标签,回归拟合各维度权重,而非人工设定。
- 可视化:输出雷达图(4 维度)+ 热区叠加图,直观展示互补性。
如果你能提供现有数据库结构(比如是否已有事件级数据、热区是否已采集),我可以把上面的表设计和算法进一步贴合你的真实字段来改。
版权声明:本站文章为原创整理,转载请注明出处。