java案例统计斜长传精准度如何?

wen java案例 1

统计斜长传精准度

需求分析

在足球数据分析中,斜长传(Diagonal Long Ball) 是指球员从中后场向对角线方向发起的长距离传球,统计其精准度是评估球员组织能力的重要指标。

java案例统计斜长传精准度如何?

核心指标:

  • 斜长传总次数
  • 成功次数(队友接到球)
  • 精准度 = 成功次数 / 总次数 × 100%

数据模型设计

传球事件实体类

public class PassEvent {
    private Long id;
    private String playerName;     // 传球球员
    private String teamName;       // 球队
    private double startX;         // 起点X坐标(0-100)
    private double startY;         // 起点Y坐标(0-100)
    private double endX;           // 终点X坐标
    private double endY;           // 终点Y坐标
    private double distance;       // 传球距离(米)
    private boolean isSuccess;     // 是否成功(队友接到)
    private int matchMinute;       // 比赛分钟
    // 判断是否为斜长传
    public boolean isDiagonalLongBall() {
        double dx = Math.abs(endX - startX);
        double dy = Math.abs(endY - startY);
        // 距离 > 25米 且 X、Y方向都有明显位移(角度在20°-70°之间)
        double angle = Math.toDegrees(Math.atan2(dy, dx));
        return distance > 25 && dx > 10 && dy > 10 
                && angle >= 20 && angle <= 70;
    }
    // getter/setter 省略
}

统计数据类

public class PassStatistic {
    private String playerName;
    private int totalDiagonalLongBalls;
    private int successDiagonalLongBalls;
    private double accuracy;  // 精准度百分比
    public void calculateAccuracy() {
        this.accuracy = totalDiagonalLongBalls == 0 ? 0 
                : (double) successDiagonalLongBalls / totalDiagonalLongBalls * 100;
    }
}

核心统计逻辑

import java.util.*;
import java.util.stream.Collectors;
public class DiagonalPassAnalyzer {
    /**
     * 统计单个球员的斜长传精准度
     */
    public PassStatistic analyzePlayer(List<PassEvent> events, String playerName) {
        List<PassEvent> diagonalLongBalls = events.stream()
                .filter(e -> e.getPlayerName().equals(playerName))
                .filter(PassEvent::isDiagonalLongBall)
                .collect(Collectors.toList());
        PassStatistic stat = new PassStatistic();
        stat.setPlayerName(playerName);
        stat.setTotalDiagonalLongBalls(diagonalLongBalls.size());
        stat.setSuccessDiagonalLongBalls(
            (int) diagonalLongBalls.stream().filter(PassEvent::isSuccess).count()
        );
        stat.calculateAccuracy();
        return stat;
    }
    /**
     * 统计全队所有球员的斜长传精准度,并按精准度排名
     */
    public List<PassStatistic> analyzeTeam(List<PassEvent> events) {
        Map<String, List<PassEvent>> byPlayer = events.stream()
                .filter(PassEvent::isDiagonalLongBall)
                .collect(Collectors.groupingBy(PassEvent::getPlayerName));
        return byPlayer.entrySet().stream()
                .map(entry -> {
                    PassStatistic stat = new PassStatistic();
                    stat.setPlayerName(entry.getKey());
                    stat.setTotalDiagonalLongBalls(entry.getValue().size());
                    stat.setSuccessDiagonalLongBalls(
                        (int) entry.getValue().stream()
                                .filter(PassEvent::isSuccess).count()
                    );
                    stat.calculateAccuracy();
                    return stat;
                })
                .sorted(Comparator.comparingDouble(PassStatistic::getAccuracy).reversed())
                .collect(Collectors.toList());
    }
}

实战测试

public class Main {
    public static void main(String[] args) {
        // 模拟比赛数据
        List<PassEvent> events = Arrays.asList(
            buildPass("德布劳内", 30, 20, 70, 60, 55, true),
            buildPass("德布劳内", 25, 30, 65, 55, 48, false),
            buildPass("德布劳内", 40, 15, 80, 50, 50, true),
            buildPass("德布劳内", 20, 40, 60, 70, 45, true),
            buildPass("B席",      35, 25, 75, 55, 42, false),
            buildPass("B席",      30, 30, 70, 60, 38, true)
        );
        DiagonalPassAnalyzer analyzer = new DiagonalPassAnalyzer();
        PassStatistic kdb = analyzer.analyzePlayer(events, "德布劳内");
        System.out.printf("球员: %s%n", kdb.getPlayerName());
        System.out.printf("斜长传总次数: %d%n", kdb.getTotalDiagonalLongBalls());
        System.out.printf("成功次数: %d%n", kdb.getSuccessDiagonalLongBalls());
        System.out.printf("精准度: %.2f%%%n", kdb.getAccuracy());
        System.out.println("\n===== 全队排名 =====");
        analyzer.analyzeTeam(events).forEach(s -> 
            System.out.printf("%s → %.1f%% (%d/%d)%n", 
                s.getPlayerName(), s.getAccuracy(),
                s.getSuccessDiagonalLongBalls(), s.getTotalDiagonalLongBalls())
        );
    }
    private static PassEvent buildPass(String player, double sx, double sy,
            double ex, double ey, double dist, boolean success) {
        PassEvent e = new PassEvent();
        e.setPlayerName(player);
        e.setStartX(sx); e.setStartY(sy);
        e.setEndX(ex);   e.setEndY(ey);
        e.setDistance(dist);
        e.setSuccess(success);
        return e;
    }
}

输出结果:

球员: 德布劳内
斜长传总次数: 4
成功次数: 3
精准度: 75.00%
===== 全队排名 =====
德布劳内 → 75.0% (3/4)
B席       → 50.0% (1/2)

进阶扩展

按区域统计(前场/中场/后场)

public Map<String, Double> accuracyByZone(List<PassEvent> events) {
    return events.stream()
        .filter(PassEvent::isDiagonalLongBall)
        .collect(Collectors.groupingBy(
            e -> {
                if (e.getStartX() < 35) return "后场";
                if (e.getStartX() < 70) return "中场";
                return "前场";
            },
            Collectors.averagingDouble(e -> e.isSuccess() ? 100.0 : 0.0)
        ));
}

按比赛时间阶段统计

public Map<String, Double> accuracyByPhase(List<PassEvent> events) {
    return events.stream()
        .filter(PassEvent::isDiagonalLongBall)
        .collect(Collectors.groupingBy(
            e -> e.getMatchMinute() <= 30 ? "上半场前段"
               : e.getMatchMinute() <= 45 ? "上半场后段" 
               : e.getMatchMinute() <= 75 ? "下半场前段" : "下半场后段",
            Collectors.averagingDouble(e -> e.isSuccess() ? 100.0 : 0.0)
        ));
}

结合压力值(对方逼抢人数)分析

public double accuracyUnderPressure(List<PassEvent> events, int pressureLevel) {
    return events.stream()
        .filter(PassEvent::isDiagonalLongBall)
        .filter(e -> e.getPressure() >= pressureLevel)
        .mapToDouble(e -> e.isSuccess() ? 1 : 0)
        .average().orElse(0.0) * 100;
}
要素 说明
判定规则 距离 > 25m + 对角线角度 20°-70°
核心公式 精准度 = 成功数 / 总数 × 100%
数据来源 通常来自 Opta / StatsBomb / Wyscout 的 event 数据
Java 优势 Stream API 处理事件流清晰,易扩展多维分析
评估参考 顶级中场斜长传精准度一般在 65%-80% 之间

实战意义:斜长传精准度高的球员通常是球队的组织核心(如德布劳内、克罗斯),该指标可用于:

  • 球探报告球员筛选
  • 战术针对性布置(限制对方长传转移)
  • 球员状态趋势追踪

如果需要完整的 Spring Boot + MySQL 落地方案(含数据表 DDL 和 REST API),可以进一步展开。

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