本文目录导读:

我来为您创建一个足球比赛禁区内外射门统计的Python案例。
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
from matplotlib.font_manager import FontProperties
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
class FootballShotAnalyzer:
def __init__(self):
# 球场尺寸(单位:米)
self.field_length = 105
self.field_width = 68
# 禁区尺寸(标准禁区)
self.penalty_area_length = 16.5
self.penalty_area_width = 40.32
# 球门尺寸
self.goal_width = 7.32
def generate_sample_data(self):
"""生成示例射门数据"""
# 格式:球队A和球队B的射门数据
# 坐标基于进攻方向(假设进攻方向为从左到右)
team_a_shots = [
# (x坐标, y坐标, 射门结果, 球员)
(85, 30, 'goal', '前锋1'),
(88, 35, 'goal', '前锋2'),
(78, 25, 'save', '中场1'),
(92, 40, 'wide', '前锋1'),
(83, 20, 'block', '中场2'),
(95, 32, 'goal', '前锋2'),
(80, 38, 'save', '前锋1'),
(75, 28, 'wide', '中场3'),
(90, 33, 'block', '前锋3'),
(87, 37, 'save', '中场1'),
]
team_b_shots = [
(82, 32, 'goal', '前锋4'),
(79, 29, 'save', '前锋5'),
(91, 36, 'save', '中场4'),
(86, 34, 'wide', '前锋4'),
(93, 31, 'block', '前锋5'),
(77, 27, 'goal', '前锋6'),
(89, 39, 'save', '中场5'),
(84, 30, 'goal', '前锋4'),
(96, 33, 'wide', '前锋6'),
(81, 35, 'block', '中场4'),
]
return {
'team_a': {'shots': team_a_shots, 'name': '主队'},
'team_b': {'shots': team_b_shots, 'name': '客队'}
}
def is_in_penalty_area(self, x, y):
"""判断射门位置是否在禁区内"""
# 判断坐标是否在禁区内(基于进攻方向)
if x >= 105 - self.penalty_area_length: # 在禁区内
if abs(y - self.field_width/2) <= self.penalty_area_width/2:
return True
return False
def analyze_shots(self, data):
"""分析射门数据"""
analysis = {}
for team_key, team_data in data.items():
team_shots = team_data['shots']
team_name = team_data['name']
# 统计限定在对方半场(x > 50)
filter_shots = [shot for shot in team_shots if shot[0] > 50]
in_area = []
out_area = []
for shot in filter_shots:
x, y, result, player = shot
if self.is_in_penalty_area(x, y):
in_area.append(shot)
else:
out_area.append(shot)
analysis[team_key] = {
'team_name': team_name,
'in_area': in_area,
'out_area': out_area,
'in_area_count': len(in_area),
'out_area_count': len(out_area),
'in_area_goals': sum(1 for s in in_area if s[2] == 'goal'),
'out_area_goals': sum(1 for s in out_area if s[2] == 'goal')
}
return analysis
def plot_comparison(self, analysis):
"""绘制禁区内外射门对比图"""
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(14, 10))
teams = list(analysis.keys())
teams_name = [analysis[team]['team_name'] for team in teams]
in_counts = [analysis[team]['in_area_count'] for team in teams]
out_counts = [analysis[team]['out_area_count'] for team in teams]
# 1. 射门次数对比柱状图
x = np.arange(len(teams))
width = 0.35
bars1 = ax1.bar(x - width/2, in_counts, width, label='禁区内', color='#2196F3')
bars2 = ax1.bar(x + width/2, out_counts, width, label='禁区外', color='#FFC107')
ax1.set_xlabel('球队')
ax1.set_ylabel('射门次数')
ax1.set_title('禁区内外射门次数对比')
ax1.set_xticks(x)
ax1.set_xticklabels(teams_name)
ax1.legend()
# 在柱状图上添加数值
for bar in bars1:
height = bar.get_height()
ax1.text(bar.get_x() + bar.get_width()/2., height,
f'{int(height)}', ha='center', va='bottom')
for bar in bars2:
height = bar.get_height()
ax1.text(bar.get_x() + bar.get_width()/2., height,
f'{int(height)}', ha='center', va='bottom')
# 2. 饼图对比
ax2.pie([in_counts[0], out_counts[0]],
labels=['禁区内', '禁区外'],
autopct='%1.1f%%',
colors=['#2196F3', '#FFC107'])
ax2.set_title(f'{teams_name[0]}射门分布')
ax4.pie([in_counts[1], out_counts[1]],
labels=['禁区内', '禁区外'],
autopct='%1.1f%%',
colors=['#4CAF50', '#FF5722'])
ax4.set_title(f'{teams_name[1]}射门分布')
# 3. 球场示意图
self.plot_field(ax3, analysis)
plt.tight_layout()
return fig
def plot_field(self, ax, analysis):
"""绘制球场示意图"""
# 绘制球场
ax.set_xlim(0, self.field_length)
ax.set_ylim(0, self.field_width)
ax.set_aspect('equal')
ax.set_title('射门位置分布图')
# 绘制球场边界
ax.add_patch(patches.Rectangle((0, 0), self.field_length, self.field_width,
fill=False, edgecolor='green', linewidth=2))
# 绘制中线
ax.axvline(x=self.field_length/2, color='green', linewidth=1)
# 绘制禁区(右上角,进攻方向)
penalty_start = self.field_length - self.penalty_area_length
penalty_y_start = (self.field_width - self.penalty_area_width)/2
ax.add_patch(patches.Rectangle((penalty_start, penalty_y_start),
self.penalty_area_length, self.penalty_area_width,
fill=False, edgecolor='green', linewidth=1.5))
# 绘制球门
goal_y_start = (self.field_width - self.goal_width)/2
ax.plot([self.field_length, self.field_length],
[goal_y_start, goal_y_start + self.goal_width],
color='red', linewidth=3)
# 绘制各球员射门位置
colors_map = {
'team_a': '#2196F3',
'team_b': '#4CAF50'
}
markers_map = {
'goal': 'o',
'save': 's',
'wide': '^',
'block': 'D'
}
for team_key, team_data in analysis.items():
color = colors_map[team_key]
# 绘制禁区内射门
for shot in team_data['in_area']:
x, y, result, player = shot
marker = markers_map.get(result, 'o')
ax.scatter(x, y, c=color, marker=marker, s=100,
edgecolors='black', linewidths=1, alpha=0.7)
# 绘制禁区外射门
for shot in team_data['out_area']:
x, y, result, player = shot
marker = markers_map.get(result, 'o')
ax.scatter(x, y, c=color, marker=marker, s=100,
edgecolors='black', linewidths=1, alpha=1.0,
facecolors='none')
# 添加图例
legend_elements = [
plt.Line2D([0], [0], marker='o', color='w', label='进球',
markerfacecolor='blue', markersize=10),
plt.Line2D([0], [0], marker='s', color='w', label='扑出',
markerfacecolor='blue', markersize=10),
plt.Line2D([0], [0], marker='^', color='w', label='射偏',
markerfacecolor='blue', markersize=10),
plt.Line2D([0], [0], marker='D', color='w', label='被封堵',
markerfacecolor='blue', markersize=10)
]
ax.legend(handles=legend_elements, loc='upper left')
# 添加禁区标注
ax.text(penalty_start + 5, self.field_width/2 + 25, '禁区',
color='green', fontsize=10)
def print_summary(self, analysis):
"""打印分析摘要"""
print("="*60)
print("射门统计报告")
print("="*60)
for team_key, data in analysis.items():
print(f"\n{data['team_name']}统计:")
print(f" 总射门次数: {data['in_area_count'] + data['out_area_count']}")
print(f" 禁区内射门: {data['in_area_count']} 次")
print(f" 禁区外射门: {data['out_area_count']} 次")
print(f" 禁区内进球: {data['in_area_goals']} 个")
print(f" 禁区外进球: {data['out_area_goals']} 个")
if data['in_area_count'] > 0:
in_rate = data['in_area_goals'] / data['in_area_count'] * 100
print(f" 禁区内进球转化率: {in_rate:.1f}%")
if data['out_area_count'] > 0:
out_rate = data['out_area_goals'] / data['out_area_count'] * 100
print(f" 禁区外进球转化率: {out_rate:.1f}%")
print(" " + "-"*40)
print(f" 禁区内射门结果分布:")
self.print_result_distribution(data['in_area'])
print(f" 禁区外射门结果分布:")
self.print_result_distribution(data['out_area'])
def print_result_distribution(self, shots):
"""打印射门结果分布"""
results = {'goal': 0, 'save': 0, 'wide': 0, 'block': 0}
result_names = {'goal': '进球', 'save': '被扑出', 'wide': '射偏', 'block': '被封堵'}
for shot in shots:
results[shot[2]] += 1
for result, count in results.items():
if count > 0:
print(f" {result_names[result]}: {count} 次")
# 主程序
def main():
analyzer = FootballShotAnalyzer()
# 生成数据(实际使用时可以替换为自己的数据)
data = analyzer.generate_sample_data()
# 分析数据
analysis = analyzer.analyze_shots(data)
# 打印统计摘要
analyzer.print_summary(analysis)
# 绘制对比图表
fig = analyzer.plot_comparison(analysis)
plt.show()
# 额外分析:可视化对比数据表格
print("\n" + "="*60)
print("数据可视化对比表")
print("="*60)
print(f"{'指标':<20} {'主队':<15} {'客队':<15} {'差值':<10}")
print("-"*60)
team_a = analysis['team_a']
team_b = analysis['team_b']
metrics = [
('总射门次数', team_a['in_area_count'] + team_a['out_area_count'],
team_b['in_area_count'] + team_b['out_area_count']),
('禁区内射门', team_a['in_area_count'], team_b['in_area_count']),
('禁区外射门', team_a['out_area_count'], team_b['out_area_count']),
('禁区内进球', team_a['in_area_goals'], team_b['in_area_goals']),
('禁区外进球', team_a['out_area_goals'], team_b['out_area_goals'])
]
for name, a_val, b_val in metrics:
diff = a_val - b_val
diff_str = f"{diff:+d}" if diff != 0 else "0"
print(f"{name:<20} {a_val:<15} {b_val:<15} {diff_str:<10}")
if __name__ == "__main__":
main()
这个案例的主要功能:
功能特点:
- 数据模拟:生成两队的射门数据,包括位置坐标、射门结果和球员信息
- 区域判定:自动判断射门位置是否在禁区内
- 统计分析:计算禁区内外射门次数、进球率等指标
- 统计报告:打印详细的射门统计信息
- 可视化图表:
- 柱状图对比两队禁区内外射门次数
- 饼图显示每队的射门分布
- 球场示意图标注射门位置
可自定义:
您可以修改generate_sample_data()方法中的team_a_shots和team_b_shots列表来输入实际比赛数据,坐标格式为(x, y, result, player),其中x、y是球场坐标,result是射门结果(goal/save/wide/block),player是球员名。
运行程序后,您会看到详细的统计分析结果和直观的可视化图表,帮助您快速了解比赛中禁区内外射门的情况对比。