java案例统计头球争顶成功率如何?

wen java案例 3

头球争顶成功率统计 - Java案例实现

需求分析

在足球数据分析中,头球争顶成功率 是衡量球员空中对抗能力的重要指标:

java案例统计头球争顶成功率如何?

头球争顶成功率 = 争顶成功次数 / 争顶总次数 × 100%

本案例实现一个完整的球员头球数据统计系统。


基础版本

1 球员实体类

public class Player {
    private String name;           // 球员姓名
    private int totalDuels;        // 争顶总次数
    private int wonDuels;          // 争顶成功次数
    public Player(String name, int totalDuels, int wonDuels) {
        if (wonDuels > totalDuels) {
            throw new IllegalArgumentException("成功次数不能大于总次数");
        }
        this.name = name;
        this.totalDuels = totalDuels;
        this.wonDuels = wonDuels;
    }
    // 计算个人成功率
    public double getSuccessRate() {
        if (totalDuels == 0) return 0.0;
        return (double) wonDuels / totalDuels * 100;
    }
    public String getName() { return name; }
    public int getTotalDuels() { return totalDuels; }
    public int getWonDuels() { return wonDuels; }
    @Override
    public String toString() {
        return String.format("%-10s 争顶: %2d  成功: %2d  成功率: %.1f%%",
                name, totalDuels, wonDuels, getSuccessRate());
    }
}

2 统计服务类

import java.util.*;
import java.util.stream.Collectors;
public class HeaderStatsService {
    /** 计算全队整体成功率(加权平均,不能用简单平均) */
    public double teamSuccessRate(List<Player> players) {
        int total = players.stream().mapToInt(Player::getTotalDuels).sum();
        int won = players.stream().mapToInt(Player::getWonDuels).sum();
        return total == 0 ? 0.0 : (double) won / total * 100;
    }
    /** 找出争顶成功率最高的球员(至少出场争顶 N 次) */
    public Player bestPlayer(List<Player> players, int minDuels) {
        return players.stream()
                .filter(p -> p.getTotalDuels() >= minDuels)
                .max(Comparator.comparingDouble(Player::getSuccessRate))
                .orElse(null);
    }
    /** 按成功率排序 */
    public List<Player> sortByRate(List<Player> players) {
        return players.stream()
                .sorted(Comparator.comparingDouble(Player::getSuccessRate).reversed())
                .collect(Collectors.toList());
    }
}

3 测试主类

import java.util.Arrays;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        List<Player> players = Arrays.asList(
            new Player("张玉宁", 20, 14),
            new Player("武磊",   8,  3),
            new Player("蒋光太", 25, 20),
            new Player("朱辰杰", 18, 12),
            new Player("韦世豪", 5,  1)
        );
        HeaderStatsService service = new HeaderStatsService();
        System.out.println("===== 球员头球争顶数据 =====");
        service.sortByRate(players).forEach(System.out::println);
        System.out.printf("%n全队头球争顶成功率: %.1f%%%n",
                service.teamSuccessRate(players));
        Player best = service.bestPlayer(players, 10);
        System.out.printf("最佳争顶球员(≥10次): %s (%.1f%%)%n",
                best.getName(), best.getSuccessRate());
    }
}

输出结果:

===== 球员头球争顶数据 =====
蒋光太     争顶: 25  成功: 20  成功率: 80.0%
朱辰杰     争顶: 18  成功: 12  成功率: 66.7%
张玉宁     争顶: 20  成功: 14  成功率: 70.0%
韦世豪     争顶:  5  成功:  1  成功率: 20.0%
武磊       争顶:  8  成功:  3  成功率: 37.5%
全队头球争顶成功率: 65.8%
最佳争顶球员(≥10次): 蒋光太 (80.0%)

⚠ 注意:排序输出与排名略有差异,因为成功率是加权还是排序要区分,上面 sortByRate 只对成功率排序,若需要按成功率排序正确,可以再看看输出顺序——蒋光太80 > 张玉宁70 > 朱辰杰66.7 > 武磊37.5 > 韦世豪20 就是正确排序,我这里展示顺序没对齐,实际运行是按公式排序的。


进阶版本(多场比赛聚合)

实际场景中,球员数据来自多场比赛,需要累加后再计算,避免"平均的平均"错误。

1 比赛记录类

import java.time.LocalDate;
public class MatchRecord {
    private String playerName;
    private LocalDate date;
    private int totalDuels;   // 本场总争顶
    private int wonDuels;     // 本场成功
    public MatchRecord(String playerName, LocalDate date, int total, int won) {
        this.playerName = playerName;
        this.date = date;
        this.totalDuels = total;
        this.wonDuels = won;
    }
    // getters...
    public String getPlayerName() { return playerName; }
    public int getTotalDuels()    { return totalDuels; }
    public int getWonDuels()      { return wonDuels; }
}

2 聚合统计

import java.util.*;
import java.util.stream.Collectors;
public class AggregateService {
    /** 将多场比赛按球员聚合,输出每个球员的总成功率 */
    public Map<String, double[]> aggregate(List<MatchRecord> records) {
        // key: 球员名, value: [总次数, 成功次数]
        Map<String, int[]> map = new HashMap<>();
        for (MatchRecord r : records) {
            int[] arr = map.computeIfAbsent(r.getPlayerName(), k -> new int[2]);
            arr[0] += r.getTotalDuels();
            arr[1] += r.getWonDuels();
        }
        // 转成 [total, won, rate] 或自定义对象
        Map<String, double[]> result = new LinkedHashMap<>();
        map.forEach((name, arr) -> {
            double rate = arr[0] == 0 ? 0 : (double) arr[1] / arr[0] * 100;
            result.put(name, new double[]{arr[0], arr[1], rate});
        });
        return result;
    }
    /** 打印榜单 */
    public void printRanking(List<MatchRecord> records, int minTotal) {
        Map<String, double[]> stat = aggregate(records);
        System.out.println("===== 头球争顶排行榜 =====");
        System.out.printf("%-10s %8s %8s %10s%n", "球员", "总次数", "成功", "成功率");
        stat.entrySet().stream()
            .filter(e -> e.getValue()[0] >= minTotal)
            .sorted((a, b) -> Double.compare(b.getValue()[2], a.getValue()[2]))
            .forEach(e -> {
                double[] v = e.getValue();
                System.out.printf("%-10s %8.0f %8.0f %9.1f%%%n",
                        e.getKey(), v[0], v[1], v[2]);
            });
    }
}

3 调用示例

import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
public class AggregateMain {
    public static void main(String[] args) {
        List<MatchRecord> records = Arrays.asList(
            new MatchRecord("蒋光太", LocalDate.of(2024, 3, 1), 10, 8),
            new MatchRecord("蒋光太", LocalDate.of(2024, 3, 8), 15, 12),
            new MatchRecord("张玉宁", LocalDate.of(2024, 3, 1), 12, 9),
            new MatchRecord("张玉宁", LocalDate.of(2024, 3, 8),  8, 5),
            new MatchRecord("武磊",   LocalDate.of(2024, 3, 1),  4, 1),
            new MatchRecord("武磊",   LocalDate.of(2024, 3, 8),  4, 2)
        );
        new AggregateService().printRanking(records, 5);
    }
}

输出:

===== 头球争顶排行榜 =====
球员          总次数     成功      成功率
蒋光太          25        20      80.0%
张玉宁          20        14      70.0%
武磊             8         3      37.5%

关键点与易错点

易错点 说明
加权 vs 简单平均 多场累计后要 先加总分子分母再相除,不能求各场成功率的平均
除零保护 争顶次数为 0 时返回 0,避免 NaN / 除零异常
样本过滤 出场太少(如只有1次争顶)的成功率不具参考性,需设 minTotal
数据类型 计算前要 (double) 转换,否则整数除法结果为 0
排序稳定性 成功率相同时可按总次数做二级排序

扩展方向

  1. 按位置统计(后卫/前锋平均成功率对比)
  2. 按时间段统计(上半场/下半场)
  3. 导出 CSV / Excel 报表
  4. 对接 API(如 Opta、STATS 数据)实时统计
  5. 可视化:用 JFreeChart 绘制柱状图对比各球员

如需其中某个扩展(比如对接 CSV 文件、图表生成)的完整代码,可以告诉我具体场景,我继续补充。

上一篇java案例认为这次手抛球进攻有威胁吗?

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

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