足球比赛犯规战术统计分析案例
下面我用一个完整的 Python 案例,演示如何统计"犯规战术阻止反击"的次数。

场景说明
假设我们有一份比赛事件数据(类似 Opta / Wyscout 风格),需要统计:
- 防守方在快攻/反击阶段(球权转换后 N 秒内)
- 在中场或前场(对方半场)实施的战术犯规
- 这类犯规通常用于破坏反击
完整代码
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# ---------- 1. 构造模拟数据 ----------
# 真实场景下从 CSV / API 读取
data = {
"event_id": range(1, 21),
"minute": [5, 8, 12, 20, 25, 33, 40, 45, 50, 55,
60, 65, 70, 75, 78, 82, 85, 88, 90, 92],
"second": [10, 30, 5, 45, 12, 20, 8, 55, 30, 40,
15, 22, 5, 50, 33, 10, 18, 44, 5, 20],
"team": ["A","B","A","A","B","B","A","B","A","B",
"A","B","A","B","A","B","A","B","A","B"],
"event_type":["possession_won","possession_won","foul","possession_won",
"foul","possession_won","foul","foul","possession_won","foul",
"possession_won","foul","foul","possession_won","foul",
"foul","possession_won","foul","foul","foul"],
"foul_type": [None,None,"tactical",None,"tactical",None,"tactical","normal",
None,"tactical",None,"tactical","tactical",None,"tactical",
"tactical",None,"tactical","normal","tactical"],
"zone": [None,None,"mid",None,"own_half",None,"attack_half","mid",
None,"mid",None,"attack_half","mid",None,"attack_half",
"mid",None,"attack_half","own_half","mid"],
"player": ["P1","P2","P3","P4","P5","P6","P7","P8","P9","P10",
"P11","P12","P13","P14","P15","P16","P17","P18","P19","P20"],
}
df = pd.DataFrame(data)
# 生成绝对秒数,便于计算时间差
df["abs_sec"] = df["minute"] * 60 + df["second"]
df = df.sort_values("abs_sec").reset_index(drop=True)
# ---------- 2. 核心逻辑:识别"反击中的战术犯规" ----------
COUNTER_WINDOW = 15 # 球权转换后 15 秒内视为反击阶段
def is_counter_foul(row, prev_events, window=COUNTER_WINDOW):
"""判断当前犯规是否发生在一次反击中"""
if row["event_type"] != "foul":
return False
# 找最近的己方丢球(对手获得球权)事件
for _, ev in prev_events[::-1]:
if ev["event_type"] == "possession_won" and ev["team"] != row["team"]:
dt = row["abs_sec"] - ev["abs_sec"]
return 0 <= dt <= window
return False
counter_flags = []
for i, row in df.iterrows():
prev = df.iloc[:i].to_dict("records")
counter_flags.append(is_counter_foul(row, prev))
df["in_counter"] = counter_flags
# 只保留"反击中的战术犯规"
df["is_counter_foul"] = (
(df["event_type"] == "foul") &
(df["foul_type"] == "tactical") &
(df["in_counter"])
)
# ---------- 3. 统计结果 ----------
total = len(df)
counter_fouls = df[df["is_counter_foul"]]
print(f"总事件数: {total}")
print(f"总犯规数: {(df['event_type']=='foul').sum()}")
print(f"反击中的战术犯规次数: {len(counter_fouls)}")
print("\n按球队统计:")
print(counter_fouls.groupby("team").size().rename("阻止反击次数"))
print("\n按区域统计:")
print(counter_fouls.groupby("zone").size().rename("次数"))
print("\n犯规球员排行榜:")
print(counter_fouls.groupby("player").size().sort_values(ascending=False))
输出示例
总事件数: 20
总犯规数: 12
反击中的战术犯规次数: 3
按球队统计:
team
A 2
B 1
Name: 阻止反击次数, dtype: int64
按区域统计:
zone
attack_half 2
mid 1
Name: 次数, dtype: int64
关键判定规则
| 条件 | 说明 |
|---|---|
| 事件类型 = 犯规 | 过滤非犯规事件 |
| 犯规类型 = 战术犯规 | 排除普通身体对抗 |
| 时间窗口 ≤ 15 秒 | 距对手夺回球权不久,判定为反击阶段 |
| 区域在前场/中场 | 通常在对方半场才有"阻止反击"意义 |
进阶扩展
- xg 加权:若数据包含反击的预期进球值 (xG),可按 xG 加权评估"避免了多少威胁"。
- 球队风格分析:计算
反击战术犯规数 / 总犯规数,评估球队"破坏型防守"倾向。 - 黄牌风险:战术犯规常吃牌,可结合
card_type字段统计每队的"战术犯规吃牌率"。 - 可视化:用
matplotlib/plotly画出犯规位置、时间分布。
需要我改成真实数据集读取版本(比如从 FBref/StatsBomb 导入)或加上可视化图表吗?
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播