本文目录导读:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
足球传球长短传比例统计脚本
支持从CSV或纯文本数据中读取传球记录,统计短传/中传/长传的比例分布。
"""
import csv
import sys
import os
from collections import Counter
from typing import List, Dict, Tuple
# ==================== 配置参数 ====================
# 传球距离分类阈值(单位:码或米,请根据你的数据统一单位)
SHORT_PASS_MAX = 15 # 小于等于此距离为短传
LONG_PASS_MIN = 30 # 大于等于此距离为长传
# 中间范围(15 < 距离 < 30)自动归为中传
# ==================== 核心统计函数 ====================
def classify_pass(distance: float) -> str:
"""根据距离对传球进行分类"""
if distance <= SHORT_PASS_MAX:
return "短传"
elif distance >= LONG_PASS_MIN:
return "长传"
else:
return "中传"
def parse_csv(file_path: str) -> List[float]:
"""从CSV文件中读取传球距离数据(支持'distance'列或第一列)"""
distances = []
try:
with open(file_path, 'r', encoding='utf-8') as f:
# 使用DictReader自动读取表头
reader = csv.DictReader(f)
# 如果CSV没有表头,则手动指定第一列为距离
if not reader.fieldnames:
f.seek(0)
reader = csv.reader(f)
for row in reader:
if row and row[0].strip():
try:
distances.append(float(row[0]))
except ValueError:
print(f"警告: 无法解析行 '{row}' 中的数据,已跳过")
else:
# 优先查找常见列名
distance_col = None
possible_names = ['distance', 'Distance', '距离', 'pass_length', 'length', 'dist']
for name in possible_names:
if name in reader.fieldnames:
distance_col = name
break
if not distance_col:
# 默认使用第一列
distance_col = reader.fieldnames[0]
print(f"提示: 未找到标准距离列名,默认使用 '{distance_col}' 列")
for row in reader:
try:
val = row[distance_col].strip()
if val:
distances.append(float(val))
except (ValueError, KeyError):
print(f"警告: 第 {reader.line_num} 行距离数据无效")
except FileNotFoundError:
print(f"错误: 文件 '{file_path}' 不存在")
sys.exit(1)
except Exception as e:
print(f"读取文件时发生错误: {e}")
sys.exit(1)
return distances
def parse_txt(file_path: str) -> List[float]:
"""从纯文本文件中读取数字(每行一个距离,或空格分隔)"""
distances = []
try:
with open(file_path, 'r', encoding='utf-8') as f:
for line_num, line in enumerate(f, 1):
# 支持逗号或空格分隔的多值行
parts = line.replace(',', ' ').split()
for part in parts:
try:
distances.append(float(part))
except ValueError:
print(f"警告: 第 {line_num} 行 '{part}' 不是有效数字,已忽略")
except FileNotFoundError:
print(f"错误: 文件 '{file_path}' 不存在")
sys.exit(1)
return distances
def load_data(file_path: str) -> List[float]:
"""根据文件扩展名自动选择解析方法"""
ext = os.path.splitext(file_path)[1].lower()
if ext == '.csv':
return parse_csv(file_path)
else: # 默认按文本处理
return parse_txt(file_path)
def compute_distribution(distances: List[float]) -> Tuple[Dict[str, int], Dict[str, float]]:
"""计算长短传比例分布"""
if not distances:
print("错误: 没有有效的传球距离数据")
sys.exit(1)
# 统计分类
classification = Counter(classify_pass(d) for d in distances)
total = len(distances)
# 计算百分比
percentages = {k: (v / total) * 100 for k, v in classification.items()}
return classification, percentages
# ==================== 输出格式化 ====================
def print_report(distances: List[float], counts: Dict[str, int], percentages: Dict[str, float]):
"""打印清晰的分析报告"""
total = len(distances)
print("\n" + "="*50)
print(f"传球距离统计分析报告")
print("="*50)
print(f"总传球次数: {total}")
print(f"分类标准: 短传 ≤ {SHORT_PASS_MAX} | 中传 ({SHORT_PASS_MAX} < d < {LONG_PASS_MIN}) | 长传 ≥ {LONG_PASS_MIN}")
print("-"*50)
# 按顺序输出三类
for category in ['短传', '中传', '长传']:
count = counts.get(category, 0)
pct = percentages.get(category, 0)
bar_len = int(pct / 2) # 简化可视化,每'#'代表2%
print(f"{category}: {count:5d} 次 ({pct:5.1f}%) {'#' * bar_len}")
# 额外统计信息
print("-"*50)
if distances:
avg = sum(distances) / len(distances)
max_d = max(distances)
min_d = min(distances)
print(f"平均传球距离: {avg:.1f}")
print(f"最长传球: {max_d:.1f}")
print(f"最短传球: {min_d:.1f}")
# 长短传比值(短传/长传)
short = counts.get('短传', 0)
long = counts.get('长传', 0)
if long > 0:
ratio = short / long
print(f"短传/长传比例: {ratio:.2f} : 1")
else:
print("短传/长传比例: 无长传数据")
print("="*50)
# ==================== 主程序入口 ====================
def main():
# 命令行参数处理
if len(sys.argv) < 2:
print("用法: python pass_analysis.py <数据文件> [--thresholds 短传阈值 长传阈值]")
print("示例: python pass_analysis.py passes.csv")
print(" python pass_analysis.py passes.txt --thresholds 10 25")
sys.exit(1)
file_path = sys.argv[1]
# 可选阈值参数
global SHORT_PASS_MAX, LONG_PASS_MIN
if '--thresholds' in sys.argv:
idx = sys.argv.index('--thresholds')
try:
SHORT_PASS_MAX = float(sys.argv[idx+1])
LONG_PASS_MIN = float(sys.argv[idx+2])
except (IndexError, ValueError):
print("错误: --thresholds 需要两个数值参数")
sys.exit(1)
# 加载数据
print(f"正在读取文件: {file_path}")
distances = load_data(file_path)
print(f"成功读取 {len(distances)} 条传球数据")
# 统计与输出
counts, percentages = compute_distribution(distances)
print_report(distances, counts, percentages)
if __name__ == "__main__":
main()
使用方法
-
数据准备:将传球距离数据保存为 CSV 或纯文本文件
- CSV 格式示例(支持
distance列名或直接用第一列):distance 12.5 28.3 45.2 8.7
- 纯文本格式示例(每行一个数字,或空格分隔):
5 28.3 45.2 8.7 19.4 33.1
- CSV 格式示例(支持
-
运行脚本:
python pass_analysis.py 传球数据.csv
-
自定义阈值(可选):
python pass_analysis.py 传球数据.csv --thresholds 10 25
输出示例
==================================================
传球距离统计分析报告
==================================================
总传球次数: 156
分类标准: 短传 ≤ 15 | 中传 (15 < d < 30) | 长传 ≥ 30
--------------------------------------------------
短传: 78 次 ( 50.0%) #########################
中传: 52 次 ( 33.3%) #################
长传: 26 次 ( 16.7%) #########
--------------------------------------------------
平均传球距离: 21.4
最长传球: 67.2
最短传球: 3.1
短传/长传比例: 3.00 : 1
==================================================
功能特点
- 自动识别文件类型:根据扩展名选择解析方式
- 灵活阈值设置:通过命令行参数调整长短传分类标准
- 容错处理:自动跳过无效数据并给出警告
- 可视化输出:用条状图直观展示比例分布
- 额外统计:包含平均距离、最大/最小值和短长传比值
您可以根据实际数据格式调整 parse_csv 和 parse_txt 函数,或修改分类阈值来适配您的分析需求。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
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直播