本文目录导读:

识别球队战术风格,是足球数据分析中比较有意思的一个方向,下面从数据采集、特征工程、风格分类、实战脚本四个层面,给出一套可落地的方案。
战术风格的分类框架
先把“风格”定义成可量化的维度,常见的分类体系:
| 风格类型 | 核心特征 |
|---|---|
| 控球渗透型 | 高控球率、短传多、推进慢、传球网络密集 |
| 高位逼抢型 | 高PPDA(防守动作/对方传球)、前场夺回球权多、防线高 |
| 防守反击型 | 低控球、长传比例高、进攻转换速度快、射门转化率高 |
| 直接长传型 | 长传占比高、空中对抗多、二点球争夺激烈 |
| 边路传中型 | 传中次数高、边路进攻占比大、禁区内触球多 |
| 定位球依赖型 | 定位球进球占比高、角球/任意球战术复杂 |
数据来源
- 公开数据:FBref(StatsBomb数据)、Understat(xG)、WhoScored、SofaScore
- 事件数据:StatsBomb Open Data、Wyscout(付费)
- 追踪数据:Metrica Sports(开源样本)
- API 抓取:
requests+BeautifulSoup或soccerdata库
# 示例:用 soccerdata 拉取 FBref 球队数据 import soccerdata as sd fbref = sd.FBref(leagues="ENG-Premier League", seasons="2023-2024") team_stats = fbref.read_team_season_stats(stat_type="passing")
特征工程(关键)
从原始数据构建风格指纹向量:
features = {
# 控球维度
"possession": 控球率,
"passes_per_game": 场均传球,
"short_pass_ratio": 短传占比,
"progressive_passes": 推进传球数,
# 压迫维度
"ppda": 防守动作/对方传球, # 越低压迫越强
"high_turnovers": 前场夺回球权,
"defensive_line_height": 平均防线高度,
# 直接性维度
"long_pass_ratio": 长传占比,
"direct_speed": 进攻推进速度(m/s),
"passes_per_possession": 每次控球传球数,
# 进攻方式
"cross_ratio": 传中占比,
"central_attack_ratio": 中路进攻占比,
"set_piece_xg_share": 定位球xG占比,
# 转换效率
"counter_attack_shots": 反击射门数,
"shots_per_possession": 每次控球射门数,
}
风格识别脚本(三种方法)
方法1:规则阈值法(快速、可解释)
def classify_style(f):
if f["possession"] > 0.58 and f["short_pass_ratio"] > 0.75:
return "控球渗透型"
if f["ppda"] < 9 and f["high_turnovers"] > 8:
return "高位逼抢型"
if f["possession"] < 0.45 and f["counter_attack_shots"] > 3:
return "防守反击型"
if f["long_pass_ratio"] > 0.20:
return "直接长传型"
if f["cross_ratio"] > 0.25:
return "边路传中型"
return "均衡型"
方法2:聚类法(无监督,发现风格群)
from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans import pandas as pd # df: 每行一支球队,每列一个特征 X = StandardScaler().fit_transform(df[feature_cols]) km = KMeans(n_clusters=6, random_state=42, n_init=10) df["cluster"] = km.fit_predict(X) # 用雷达图/聚类中心解释每个群 centers = pd.DataFrame(km.cluster_centers_, columns=feature_cols) print(centers)
方法3:监督分类(有标签时)
用历史标注数据训练 RandomForest / XGBoost,输出风格概率:
from sklearn.ensemble import RandomForestClassifier clf = RandomForestClassifier(n_estimators=300, random_state=42) clf.fit(X_train, y_train) # 可解释性:特征重要性 importances = pd.Series(clf.feature_importances_, index=feature_cols).sort_values(ascending=False)
可视化:风格雷达图
import matplotlib.pyplot as plt
import numpy as np
def radar_chart(team_features, labels, title):
N = len(labels)
angles = np.linspace(0, 2*np.pi, N, endpoint=False).tolist()
values = team_features + team_features[:1]
angles += angles[:1]
fig, ax = plt.subplots(figsize=(6,6), subplot_kw=dict(polar=True))
ax.plot(angles, values, linewidth=2)
ax.fill(angles, values, alpha=0.25)
ax.set_xticks(angles[:-1])
ax.set_xticklabels(labels)
ax.set_title(title)
plt.show()
实战分层建议
| 阶段 | 做法 |
|---|---|
| 快速初筛 | 规则阈值 + 雷达图,看 3–5 个核心维度 |
| 联赛横向对比 | KMeans/分层聚类,得到 5–8 种风格群 |
| 对手针对性分析 | 计算与目标风格的“距离”(欧氏距离/余弦相似度) |
| 动态风格追踪 | 按滚动窗口(如10场)计算特征,看风格漂移 |
距离匹配示例:
from scipy.spatial.distance import cosine target = style_vectors["高位逼抢型"] similarity = 1 - cosine(team_vector, target)
注意事项
- 样本量:单赛季 38 场样本偏小,建议用 2–3 赛季滚动数据。
- 对手强度校正:需对“对强队 vs 弱队”的风格差异做归一化。
- 主客场差异:分开建模更准确。
- 风格会漂移:换教练、核心球员伤停都会改变风格,需滚动更新。
- 混合风格:多数球队是“主风格 + 副风格”,用概率分布比单标签更贴近现实。
如果需要,我可以进一步给出一个完整的可运行脚本(含 FBref 抓取 → 特征计算 → 聚类 → 雷达图),或针对某个联赛/球队做具体实现,你更想先看哪一部分?
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播