PHP项目统计斜长传精准度方案
斜长传(Cross-field long pass / Diagonal long ball)的精准度统计,核心是判定传球是否成功到达目标区域/队友脚下,下面给出完整的设计思路和 PHP 实现。

指标定义
| 指标 | 说明 |
|---|---|
| 斜长传次数 | 起点到终点距离 ≥ 30m 且角度在 25°~65° 之间的传球 |
| 成功斜长传 | 传球后接球队友成功控球(未被对手拦截/出界) |
| 精准度 | 成功次数 / 总次数 × 100% |
| 落点偏差 | 实际落点与目标点距离(可选,用于精细化) |
数据模型
CREATE TABLE passes (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
match_id INT NOT NULL,
player_id INT NOT NULL,
team_id INT NOT NULL,
start_x DECIMAL(6,2), -- 场地坐标(米)
start_y DECIMAL(6,2),
end_x DECIMAL(6,2),
end_y DECIMAL(6,2),
pass_type ENUM('short','long','cross','diagonal_long') DEFAULT 'short',
is_success TINYINT(1) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_match_player (match_id, player_id)
);
核心判定逻辑(PHP)
class DiagonalPassAnalyzer
{
private const MIN_DISTANCE = 30.0; // 最小长传距离(米)
private const MIN_ANGLE = 25.0; // 最小角度
private const MAX_ANGLE = 65.0; // 最大角度(相对球场纵轴)
/**
* 判断一次传球是否为斜长传
*/
public function isDiagonalLongPass(array $pass): bool
{
$dx = $pass['end_x'] - $pass['start_x'];
$dy = $pass['end_y'] - $pass['start_y'];
$distance = sqrt($dx * $dx + $dy * $dy);
if ($distance < self::MIN_DISTANCE) {
return false;
}
// 角度:相对球场纵轴(y 轴)的夹角
// 用 atan2 求与 y 轴夹角,再转角度
$angle = rad2deg(atan2(abs($dx), abs($dy)));
return $angle >= self::MIN_ANGLE && $angle <= self::MAX_ANGLE;
}
/**
* 统计某球员斜长传精准度
*/
public function playerAccuracy(PDO $pdo, int $playerId, ?int $matchId = null): array
{
$sql = "SELECT start_x, start_y, end_x, end_y, is_success
FROM passes WHERE player_id = :pid";
$params = [':pid' => $playerId];
if ($matchId !== null) {
$sql .= " AND match_id = :mid";
$params[':mid'] = $matchId;
}
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$total = 0;
$success = 0;
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if (!$this->isDiagonalLongPass($row)) {
continue;
}
$total++;
if ((int)$row['is_success'] === 1) {
$success++;
}
}
return [
'player_id' => $playerId,
'total' => $total,
'success' => $success,
'accuracy' => $total > 0 ? round($success / $total * 100, 2) : 0.0,
];
}
}
SQL 版批量统计(性能更好)
如果不想逐条在 PHP 里算,可用 SQL 直接聚合:
SELECT
player_id,
COUNT(*) AS total,
SUM(is_success) AS success,
ROUND(SUM(is_success) / COUNT(*) * 100, 2) AS accuracy
FROM passes
WHERE match_id = ?
AND SQRT(POW(end_x - start_x, 2) + POW(end_y - start_y, 2)) >= 30
AND DEGREES(ATAN2(ABS(end_x - start_x), ABS(end_y - start_y))) BETWEEN 25 AND 65
GROUP BY player_id
ORDER BY accuracy DESC;
注意:
POW/ATAN2/DEGREES在 MySQL、PostgreSQL 都支持,PostgreSQL 需改用power、atan2(或atan(y,x))、degrees。
进阶:落点精度评价
如果数据里有目标点和实际落点,可量化精准度而非简单二值:
public function landingDeviation(array $pass): float
{
$dx = $pass['actual_x'] - $pass['target_x'];
$dy = $pass['actual_y'] - $pass['target_y'];
return sqrt($dx * $dx + $dy * $dy); // 米
}
// 可定义等级
// < 3m 优秀,3-8m 良好,8-15m 一般,>15m 失误
数据来源建议
- GPS/光学追踪数据(StatsBomb、Opta、Tracab)—— 最准确,提供坐标和接球归属。
- 事件流 JSON 导入 —— 建立 ETL 将事件转为
passes表。 - 手动标注 —— 适合业余球队,提供简易录入页面。
图表展示
- 用 Chart.js / ECharts 展示球员斜长传热力图(起点-终点连线)
- 累计精准度趋势折线图
- 队内排行榜
// 简单接口输出 JSON 给前端
header('Content-Type: application/json');
echo json_encode((new DiagonalPassAnalyzer())->playerAccuracy($pdo, 7));
关键点提示
- 角度定义要和你的场地坐标系一致(这里假设 y 轴为球场长度方向)。
- 斜长传的阈值(30m / 25°-65°)需按联赛水平校准,青训和成人队标准不同。
- "成功"定义很关键:是被本方接到,还是未被对方拦截?建议以接球为准。
- 大量数据建议预计算,把判别结果写入
is_diagonal_long字段并加索引,避免实时SQRT/POW。
如果你能说明数据字段(是否有接球人、目标点、坐标单位)和数据库类型,我可以给出更贴合的 schema 和查询。
版权声明:本站文章为原创整理,转载请注明出处。