统计"马赛回旋"使用频率的 Python 案例
"马赛回旋"(Marseille Turn / Roulette)是足球中齐达内的标志性过人动作,下面我给出一个完整可运行的 Python 案例,模拟从比赛事件数据中统计马赛回旋的使用频率。

项目背景
假设你有一份足球比赛事件记录数据(类似 StatsBomb、Opta 格式),需要统计:
- 每场比赛马赛回旋使用次数
- 每名球员使用频率
- 球队层面统计
- 使用成功率
数据准备(模拟数据)
import pandas as pd
import numpy as np
from collections import Counter
# 模拟比赛事件数据
np.random.seed(42)
players = {
"Messi": "Inter Miami",
"Zidane": "Real Madrid",
"Neymar": "Al Hilal",
"Mbappe": "Real Madrid",
"Bellingham": "Real Madrid",
"Vinicius": "Real Madrid",
"Musiala": "Bayern",
"Kvaratskhelia": "PSG",
}
events = []
match_ids = [f"M{i:03d}" for i in range(1, 11)] # 10场比赛
for match in match_ids:
for player, team in players.items():
# 每场该球员的过人事件数(泊松分布)
n_dribbles = np.random.poisson(6)
for _ in range(n_dribbles):
# 5% 概率是马赛回旋
is_marseille = np.random.random() < 0.05
success = np.random.random() < (0.75 if is_marseille else 0.6)
events.append({
"match_id": match,
"player": player,
"team": team,
"event_type": "Marseille Turn" if is_marseille else "Other Dribble",
"success": success,
"minute": np.random.randint(1, 91),
})
df = pd.DataFrame(events)
print(f"总事件数: {len(df)}")
print(df.head())
核心统计分析
# 1. 全局使用频率
total_dribbles = df[df["event_type"].isin(["Marseille Turn", "Other Dribble"])].shape[0]
marseille_count = df[df["event_type"] == "Marseille Turn"].shape[0]
global_rate = marseille_count / total_dribbles
print(f"\n【全局统计】")
print(f"所有过人事件: {total_dribbles}")
print(f"马赛回旋次数: {marseille_count}")
print(f"使用频率: {global_rate:.2%}")
# 2. 按球员统计
player_stats = df.groupby("player").agg(
total_dribbles=("event_type", "size"),
marseille_count=("event_type", lambda x: (x == "Marseille Turn").sum()),
marseille_success=(
"success",
lambda x: df.loc[x.index][df.loc[x.index, "event_type"] == "Marseille Turn"]["success"].sum()
),
)
# 修正:更清晰的写法
player_stats = df.groupby("player").apply(
lambda g: pd.Series({
"总过人": len(g),
"马赛回旋次数": (g["event_type"] == "Marseille Turn").sum(),
"使用频率": (g["event_type"] == "Marseille Turn").mean(),
"成功率": g[g["event_type"] == "Marseille Turn"]["success"].mean()
if (g["event_type"] == "Marseille Turn").sum() > 0 else np.nan,
}),
include_groups=False
).sort_values("马赛回旋次数", ascending=False)
print("\n【球员统计】")
print(player_stats.round(3))
# 3. 球队层面统计
team_stats = df.groupby("team").agg(
总过人=("event_type", "size"),
马赛回旋次数=("event_type", lambda x: (x == "Marseille Turn").sum()),
).assign(使用频率=lambda x: x["马赛回旋次数"] / x["总过人"])
team_stats = team_stats.sort_values("使用频率", ascending=False)
print("\n【球队统计】")
print(team_stats.round(3))
# 4. 按比赛统计
match_stats = df.groupby("match_id").agg(
马赛回旋次数=("event_type", lambda x: (x == "Marseille Turn").sum()),
总事件=("event_type", "size"),
)
match_stats["场均频率"] = match_stats["马赛回旋次数"] / match_stats["总事件"]
print("\n【各场比赛统计】")
print(match_stats.round(3))
可视化
import matplotlib.pyplot as plt
import matplotlib as mpl
# 中文字体设置
mpl.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei", "Arial Unicode MS"]
mpl.rcParams["axes.unicode_minus"] = False
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 左图:球员马赛回旋次数
player_stats["马赛回旋次数"].plot(
kind="barh", ax=axes[0], color="steelblue"
)
axes[0].set_title("各球员马赛回旋使用次数")
axes[0].set_xlabel("次数")
axes[0].invert_yaxis()
# 右图:球员使用频率
player_stats["使用频率"].sort_values().plot(
kind="barh", ax=axes[1], color="coral"
)
axes[1].set_title("各球员马赛回旋使用频率(占个人过人比例)")
axes[1].set_xlabel("频率")
axes[1].xaxis.set_major_formatter(mpl.ticker.PercentFormatter(xmax=1))
plt.tight_layout()
plt.savefig("marseille_turn_stats.png", dpi=150)
plt.show()
关键指标解读
| 指标 | 含义 | 合理区间 |
|---|---|---|
| 全局使用频率 | 马赛回旋占所有过人比例 | 3%–8% |
| 球员使用频率 | 该球员的偏好程度 | 0%–15% |
| 成功率 | 马赛回旋成功完成比例 | 60%–80% |
| 场均次数 | 每场平均使用 | 1–3 次 |
接入真实数据的建议
如果你有真实数据源,只需替换 df 的构造部分:
# StatsBomb 示例(需要安装 statsbombpy)
from statsbombpy import sb
events = sb.events(match_id=3788741)
df = events[events["type"] == "Dribble"].copy()
df["event_type"] = df["dribble_type"].apply(
lambda x: "Marseille Turn" if x == "Roulette" else "Other Dribble"
)
StatsBomb 中马赛回旋被标记为 dribble_type = "Roulette" 或 "Nutmeg"(需区分)。
可扩展方向
- 时空分析:马赛回旋发生在哪个区域(进攻三区占比)
- 比赛状态:领先/落后时的使用差异
- 对手强度:面对强队是否更常用
- 组合统计:马赛回旋后是否创造射门/进球(xT 值提升)
需要我针对真实 API(StatsBomb/Football-Data) 接入,或用 Plotly/Tableau 风格做交互可视化版本吗?
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播