本文目录导读:

- 核心逻辑(通用)
- 方案一:适用于 Python + Pandas(处理事件型数据)
- 方案二:适用于 JavaScript / Node.js(实时或网页分析)
- 方案三:纯 Bash / AWK(用于处理简单文本日志)
- 进阶指标(更精确的保守程度)
统计回传次数反映保守程度”这一需求,在足球数据分析、游戏AI(如FM(足球经理)或FIFA)以及战术研究中非常常见。
以下我为你提供3种不同场景下的实用脚本方案,并解释其核心逻辑。
核心逻辑(通用)
“回传”通常定义为:与上一次触球方向相比,球向本方球门方向移动的传球。 保守程度可以量化为:回传次数 / 总传球次数 或 回传频率(每分钟回传次数)。
适用于 Python + Pandas(处理事件型数据)
如果你有一份包含每次传球起止坐标和时间的 CSV/数据库,这个脚本非常实用。
import pandas as pd
def calculate_conservatism_score(df):
"""
计算回传率与保守程度
:param df: 包含传球数据的DataFrame,需包含列:
['player', 'x_start', 'y_start', 'x_end', 'y_end', 'timestamp', 'team']
:return: 返回统计结果
"""
# 示例数据加载 (假设数据已存在)
# df = pd.read_csv('passes.csv')
# 1. 计算传球方向向量(X轴正方向为进攻方向)
df['dx'] = df['x_end'] - df['x_start']
# 2. 判断是否为回传:dx < 0 即为向本方球门(假设X轴原点在本方底线)
df['is_backward'] = df['dx'] < 0
# 3. 过滤无效数据(横传或原地不动)
df_valid = df[df['dx'].abs() > 0.5] # 忽略微小位移
# 4. 按球队聚合统计
result = df_valid.groupby('team').agg(
total_passes=('dx', 'count'),
backward_passes=('is_backward', 'sum'),
avg_pass_distance=('dx', 'mean')
).reset_index()
# 5. 计算核心指标
result['backward_ratio'] = result['backward_passes'] / result['total_passes']
result['conservatism_score'] = (result['backward_ratio'] * 100).round(2)
# 6. 按保守程度排序
result = result.sort_values('conservatism_score', ascending=False)
return result
# 使用示例
# score = calculate_conservatism_score(你的DataFrame)
# print(score[['team', 'backward_ratio', 'conservatism_score']])
适用于 JavaScript / Node.js(实时或网页分析)
常用于浏览器端的战术可视化工具。
// 输入:传球数组
// 每个元素: { player: '张三', startX: 50, startY: 30, endX: 40, endY: 35, team: 'Home' }
function calculatePassConservatism(passesArray) {
const teamStats = {};
passesArray.forEach(pass => {
// 初始化或获取当前球队数据
if (!teamStats[pass.team]) {
teamStats[pass.team] = { total: 0, backward: 0, forward: 0 };
}
const stats = teamStats[pass.team];
// 判定方向(假设场地宽100米,X坐标递增代表进攻方向)
const distance = pass.endX - pass.startX;
stats.total++;
if (distance < -1) { // 阈值避免误判
stats.backward++;
} else if (distance > 1) {
stats.forward++;
}
});
// 计算最终得分
const result = Object.entries(teamStats).map(([team, stats]) => {
const ratio = stats.total > 0 ? (stats.backward / stats.total) : 0;
return {
team,
totalPasses: stats.total,
backwardPasses: stats.backward,
forwardPasses: stats.forward,
backwardRatio: ratio.toFixed(2),
conservatismLevel: ratio > 0.5 ? '极保守' : ratio > 0.3 ? '中等偏保守' : '进攻型'
};
});
return result;
}
// 调用示例
// const data = require('./passData.json');
// console.log(calculatePassConservatism(data));
纯 Bash / AWK(用于处理简单文本日志)
适用于从日志或文本文件快速提取统计。
#!/bin/bash
# 假设文件格式:team, player, startX, endX
# 每行一次传球
awk -F',' '
{
team=$1; startX=$3; endX=$4;
total[team]++; # 总传球
if (endX < startX) {
backward[team]++; # 回传计数
}
}
END {
print "Team\tTotal\tBackward\tRatio";
for (t in total) {
ratio = backward[t] / total[t] * 100;
printf "%s\t%d\t%d\t%.2f%%\n", t, total[t], backward[t], ratio;
}
}' matches_log.csv
进阶指标(更精确的保守程度)
如果需求更精细,建议在上述脚本中加入以下变量:
- 地域权重:在后场回传权重低(控制节奏),在前场回传权重高(消极比赛)。
- 时间权重:比赛最后10分钟回传比分领先,不视为保守,而是战术拖延。
- 成功率加权:如果回传传球成功率高,说明是在控制比赛,而非被动解围。
脚本调整建议:将判断条件从 is_backward 改为 is_backward AND x_start < 70(本方半场+对方30米区域),这样更接近“保守”的定义。
你目前的数据是什么样的?
- 如果是坐标数据,用方案一。
- 如果是实时预览,用方案二。
- 如果是纯文本日志,用方案三。
如果需要针对具体数据格式(如StatsBomb或Wyscout输出)进行解析,可以告诉我数据结构,我可以帮你调整列名和逻辑。