本文目录导读:

我来为你设计一个Java案例,用于统计和分析落叶球射门成功率。
落叶球射门成功率统计系统
核心模型类
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
// 射门记录类
class ShotRecord {
private Long id;
private LocalDateTime shotTime;
private double distance; // 射门距离(米)
private double angle; // 射门角度(度)
private double speed; // 球速(km/h)
private boolean isKnuckleball; // 是否落叶球
private boolean isGoal; // 是否进球
private String shotArea; // 射门区域
// 构造函数、getter/setter省略
public ShotRecord(Long id, LocalDateTime shotTime, double distance,
double angle, double speed, boolean isKnuckleball,
boolean isGoal, String shotArea) {
this.id = id;
this.shotTime = shotTime;
this.distance = distance;
this.angle = angle;
this.speed = speed;
this.isKnuckleball = isKnuckleball;
this.isGoal = isGoal;
this.shotArea = shotArea;
}
// Getters
public Long getId() { return id; }
public LocalDateTime getShotTime() { return shotTime; }
public double getDistance() { return distance; }
public double getAngle() { return angle; }
public double getSpeed() { return speed; }
public boolean isKnuckleball() { return isKnuckleball; }
public boolean isGoal() { return isGoal; }
public String getShotArea() { return shotArea; }
}
// 统计结果类
class ShotStatistics {
private int totalShots;
private int goals;
private double successRate;
private double averageSpeed;
private double averageDistance;
private Map<String, Integer> shotsByArea;
private Map<String, Integer> goalsByArea;
// Getters and Setters
public int getTotalShots() { return totalShots; }
public void setTotalShots(int totalShots) { this.totalShots = totalShots; }
public int getGoals() { return goals; }
public void setGoals(int goals) { this.goals = goals; }
public double getSuccessRate() { return successRate; }
public void setSuccessRate(double successRate) { this.successRate = successRate; }
public double getAverageSpeed() { return averageSpeed; }
public void setAverageSpeed(double averageSpeed) { this.averageSpeed = averageSpeed; }
public double getAverageDistance() { return averageDistance; }
public void setAverageDistance(double averageDistance) { this.averageDistance = averageDistance; }
public Map<String, Integer> getShotsByArea() { return shotsByArea; }
public void setShotsByArea(Map<String, Integer> shotsByArea) { this.shotsByArea = shotsByArea; }
public Map<String, Integer> getGoalsByArea() { return goalsByArea; }
public void setGoalsByArea(Map<String, Integer> goalsByArea) { this.goalsByArea = goalsByArea; }
}
统计分析服务类
import java.util.*;
import java.util.stream.Collectors;
public class ShotAnalysisService {
// 统计分析落叶球射门
public ShotStatistics analyzeKnuckleballShots(List<ShotRecord> shots) {
// 筛选出落叶球射门
List<ShotRecord> knuckleballShots = shots.stream()
.filter(ShotRecord::isKnuckleball)
.collect(Collectors.toList());
ShotStatistics stats = new ShotStatistics();
// 基础统计
stats.setTotalShots(knuckleballShots.size());
stats.setGoals((int) knuckleballShots.stream().filter(ShotRecord::isGoal).count());
stats.setSuccessRate(calculateSuccessRate(stats.getGoals(), stats.getTotalShots()));
// 计算平均球速和距离
stats.setAverageSpeed(calculateAverageSpeed(knuckleballShots));
stats.setAverageDistance(calculateAverageDistance(knuckleballShots));
// 按射门区域统计
Map<String, Integer> shotsByArea = new HashMap<>();
Map<String, Integer> goalsByArea = new HashMap<>();
for (ShotRecord shot : knuckleballShots) {
shotsByArea.merge(shot.getShotArea(), 1, Integer::sum);
if (shot.isGoal()) {
goalsByArea.merge(shot.getShotArea(), 1, Integer::sum);
}
}
stats.setShotsByArea(shotsByArea);
stats.setGoalsByArea(goalsByArea);
return stats;
}
// 计算成功率
private double calculateSuccessRate(int goals, int totalShots) {
if (totalShots == 0) return 0;
return (double) goals / totalShots * 100;
}
// 计算平均球速
private double calculateAverageSpeed(List<ShotRecord> shots) {
return shots.stream()
.mapToDouble(ShotRecord::getSpeed)
.average()
.orElse(0);
}
// 计算平均射门距离
private double calculateAverageDistance(List<ShotRecord> shots) {
return shots.stream()
.mapToDouble(ShotRecord::getDistance)
.average()
.orElse(0);
}
// 比较落叶球和非落叶球的成功率
public Map<String, Double> compareSuccessRates(List<ShotRecord> shots) {
Map<String, List<ShotRecord>> groupedByType = shots.stream()
.collect(Collectors.groupingBy(
shot -> shot.isKnuckleball() ? "落叶球" : "普通射门"
));
Map<String, Double> successRates = new HashMap<>();
groupedByType.forEach((type, shotList) -> {
int goals = (int) shotList.stream().filter(ShotRecord::isGoal).count();
double rate = calculateSuccessRate(goals, shotList.size());
successRates.put(type, rate);
});
return successRates;
}
// 分析不同距离范围的射门成功率
public Map<String, Double> analyzeByDistanceRange(List<ShotRecord> shots) {
Map<String, Double> result = new LinkedHashMap<>();
// 定义距离范围
double[] ranges = {10, 20, 30, 40, 50};
String[] labels = {"0-10m", "10-20m", "20-30m", "30-40m", "40m以上"};
for (int i = 0; i < ranges.length; i++) {
double lower = i == 0 ? 0 : ranges[i-1];
double upper = ranges[i];
List<ShotRecord> rangeShots = shots.stream()
.filter(s -> s.isKnuckleball())
.filter(s -> s.getDistance() > lower && s.getDistance() <= upper)
.collect(Collectors.toList());
if (!rangeShots.isEmpty()) {
int goals = (int) rangeShots.stream().filter(ShotRecord::isGoal).count();
result.put(labels[i], calculateSuccessRate(goals, rangeShots.size()));
} else {
result.put(labels[i], 0.0);
}
}
return result;
}
}
数据生成和测试类
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class KnuckleballTest {
// 模拟生成测试数据
private static List<ShotRecord> generateTestData(int count) {
List<ShotRecord> shots = new ArrayList<>();
Random random = new Random(42); // 固定种子便于复现
String[] areas = {"禁区左侧", "禁区中央", "禁区右侧", "禁区外左侧", "禁区外中央", "禁区外右侧"};
for (int i = 0; i < count; i++) {
Long id = (long) i;
LocalDateTime time = LocalDateTime.now().minusMinutes(random.nextInt(1000));
// 射门距离:8-35米
double distance = 8 + random.nextDouble() * 27;
// 射门角度:0-90度
double angle = random.nextDouble() * 90;
// 球速:70-120 km/h
double speed = 70 + random.nextDouble() * 50;
// 60%概率为落叶球
boolean isKnuckleball = random.nextDouble() < 0.6;
// 进球概率与距离成反比
double goalProbability = isKnuckleball ? 0.3 : 0.2;
if (distance < 15) {
goalProbability += 0.1;
} else if (distance > 25) {
goalProbability -= 0.1;
}
boolean isGoal = random.nextDouble() < goalProbability;
String area = areas[random.nextInt(areas.length)];
shots.add(new ShotRecord(id, time, distance, angle, speed,
isKnuckleball, isGoal, area));
}
return shots;
}
// 格式化输出统计结果
private static void printStatistics(ShotStatistics stats) {
System.out.println("=== 落叶球射门统计分析 ===");
System.out.println("总射门次数: " + stats.getTotalShots());
System.out.println("进球数: " + stats.getGoals());
System.out.printf("成功率: %.2f%%\n", stats.getSuccessRate());
System.out.printf("平均球速: %.2f km/h\n", stats.getAverageSpeed());
System.out.printf("平均射门距离: %.2f 米\n", stats.getAverageDistance());
System.out.println("\n射门区域统计:");
System.out.println("区域\t\t射门次数\t进球\t成功率");
stats.getShotsByArea().forEach((area, count) -> {
int goals = stats.getGoalsByArea().getOrDefault(area, 0);
double rate = count > 0 ? (double) goals / count * 100 : 0;
System.out.printf("%s\t%d\t%d\t%.2f%%\n",
area, count, goals, rate);
});
}
public static void main(String[] args) {
// 生成模拟数据(例如1000次射门)
List<ShotRecord> shots = generateTestData(1000);
ShotAnalysisService service = new ShotAnalysisService();
// 统计分析落叶球
ShotStatistics knuckleballStats = service.analyzeKnuckleballShots(shots);
printStatistics(knuckleballStats);
// 比较落叶球和普通射门
System.out.println("\n=== 成功率对比 ===");
Map<String, Double> comparison = service.compareSuccessRates(shots);
comparison.forEach((type, rate) ->
System.out.printf("%s成功率: %.2f%%\n", type, rate));
// 分析距离对成功率的影响
System.out.println("\n=== 不同距离的落叶球成功率 ===");
Map<String, Double> distanceAnalysis = service.analyzeByDistanceRange(shots);
distanceAnalysis.forEach((range, rate) ->
System.out.printf("%s: %.2f%%\n", range, rate));
// 额外分析:球速对成功率的影响
System.out.println("\n=== 球速分析 ===");
analyzeBySpeed(shots);
}
// 分析球速对成功率的影响
private static void analyzeBySpeed(List<ShotRecord> shots) {
List<ShotRecord> knuckleShots = shots.stream()
.filter(ShotRecord::isKnuckleball)
.collect(Collectors.toList());
// 按球速分档
double[][] speedRanges = {{70, 80}, {80, 90}, {90, 100}, {100, 110}, {110, 120}};
String[] labels = {"70-80km/h", "80-90km/h", "90-100km/h", "100-110km/h", "110-120km/h"};
for (int i = 0; i < speedRanges.length; i++) {
double low = speedRanges[i][0];
double high = speedRanges[i][1];
long count = knuckleShots.stream()
.filter(s -> s.getSpeed() >= low && s.getSpeed() < high)
.count();
long goals = knuckleShots.stream()
.filter(s -> s.getSpeed() >= low && s.getSpeed() < high)
.filter(ShotRecord::isGoal)
.count();
double rate = count > 0 ? (double) goals / count * 100 : 0;
System.out.printf("%s: 射门%d次, 进球%d个, 成功率%.2f%%\n",
labels[i], count, goals, rate);
}
}
}
高级功能扩展
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
// 时间序列分析类
class TimeSeriesAnalysis {
// 按月统计成功率
public Map<String, ShotStatistics> analyzeByMonth(List<ShotRecord> shots) {
return shots.stream()
.filter(ShotRecord::isKnuckleball)
.collect(Collectors.groupingBy(
shot -> shot.getShotTime().getMonth().toString(),
Collectors.collectingAndThen(
Collectors.toList(),
this::calculateStats
)
));
}
// 计算一组射门的统计
private ShotStatistics calculateStats(List<ShotRecord> shots) {
ShotStatistics stats = new ShotStatistics();
stats.setTotalShots(shots.size());
stats.setGoals((int) shots.stream().filter(ShotRecord::isGoal).count());
stats.setSuccessRate((double) stats.getGoals() / stats.getTotalShots() * 100);
return stats;
}
// 趋势分析
public Map<String, Double> analyzeTrend(List<ShotRecord> shots) {
return shots.stream()
.filter(ShotRecord::isKnuckleball)
.sorted(Comparator.comparing(ShotRecord::getShotTime))
.collect(Collectors.groupingBy(
shot -> shot.getShotTime().toLocalDate().toString(),
LinkedHashMap::new,
Collectors.collectingAndThen(
Collectors.toList(),
list -> {
int goals = (int) list.stream().filter(ShotRecord::isGoal).count();
return (double) goals / list.size() * 100;
}
)
));
}
}
// 报告生成类
class ReportGenerator {
// 生成详细报告
public String generateReport(ShotStatistics stats, Map<String, Double> comparison) {
StringBuilder report = new StringBuilder();
report.append("════════════════════════════════════════\n");
report.append(" 落叶球射门成功率分析报告\n");
report.append("════════════════════════════════════════\n\n");
report.append("【总体统计】\n");
report.append(String.format("总射门次数:%d\n", stats.getTotalShots()));
report.append(String.format("进球次数:%d\n", stats.getGoals()));
report.append(String.format("成功率:%.2f%%\n", stats.getSuccessRate()));
report.append(String.format("平均球速:%.2f km/h\n", stats.getAverageSpeed()));
report.append(String.format("平均射门距离:%.2f m\n\n", stats.getAverageDistance()));
report.append("【区域分析】\n");
report.append("区域\t\t射门数\t进球数\t成功率\n");
stats.getShotsByArea().forEach((area, count) -> {
int goals = stats.getGoalsByArea().getOrDefault(area, 0);
double rate = count > 0 ? (double) goals / count * 100 : 0;
report.append(String.format("%s\t%d\t%d\t%.2f%%\n",
area, count, goals, rate));
});
report.append("\n【成功率对比】\n");
comparison.forEach((type, rate) ->
report.append(String.format("%s:%.2f%%\n", type, rate)));
report.append("\n════════════════════════════════════════\n");
return report.toString();
}
}
使用示例
public class Main {
public static void main(String[] args) {
// 创建服务
ShotAnalysisService service = new ShotAnalysisService();
ReportGenerator reportGen = new ReportGenerator();
// 生成数据
List<ShotRecord> shots = generateTestData(2000);
// 分析
ShotStatistics stats = service.analyzeKnuckleballShots(shots);
Map<String, Double> comparison = service.compareSuccessRates(shots);
// 生成并输出报告
String report = reportGen.generateReport(stats, comparison);
System.out.println(report);
}
}
主要功能说明
- 基础统计分析:计算总射门数、进球数、成功率
- 多维分析:按区域、距离、球速等维度分析
- 对比分析:落叶球与普通射门成功率对比
- 趋势分析:按时间维度分析成功率变化
- 报告生成:自动生成统计报告
使用建议
- 数据采集:通过视频分析或传感器采集真实射门数据
- 参数调整:根据实际需求调整距离范围、球速区间
- 机器学习:可在此基础上构建预测模型,预测射门成功率
这个案例提供了完整的统计分析框架,可以根据实际需求进行扩展和定制。