
本文介绍如何从结构化文本(如网球比赛记录)中准确提取两位选手的逐盘得分,避免因简单切片导致的顺序错乱,核心是基于换行符分割并按逻辑位置分组数字行。
本文介绍如何从结构化文本(如网球比赛记录)中准确提取两位选手的逐盘得分,避免因简单切片导致的顺序错乱,核心是基于换行符分割并按逻辑位置分组数字行。
在处理体育赛事文本(尤其是网球比分)时,确保数值提取顺序与原始记录严格一致至关重要。原始方法使用 split() 将整段字符串按空格切分后,再用 numeric_parts[::2] 和 numeric_parts[1::2] 交替取值——这隐含了“得分交替出现”的错误假设,而实际文本中,选手1(如 Altmaier)的全部盘分连续出现在其姓名之后、对手姓名之前,选手2(如 Kecmanovic)的盘分则紧随其姓名之后、终场描述之前。因此,正确策略应立足于文本的行结构而非空格分隔。
✅ 推荐方案:按行解析 + 逻辑分段
由于目标数值各自独占一行(如 "4"、"4"、"6"、"6" 均为独立行),应优先使用 splitlines() 拆分,再筛选纯数字行:
def extract_player_scores(row):
lines = row['score'].splitlines()
# 提取每行均为纯数字的行(排除空行、含字母/标点的行)
numeric_lines = [line.strip() for line in lines if line.strip().isdigit()]
# 确保有偶数个有效数字行(通常为4个:p1两盘 + p2两盘)
n = len(numeric_lines)
if n == 0:
return pd.Series(["", ""])
# 前半部分属于选手1,后半部分属于选手2
mid = n // 2
p1_scores = " ".join(numeric_lines[:mid])
p2_scores = " ".join(numeric_lines[mid:])
return pd.Series([p1_scores, p2_scores])
# 应用于DataFrame
df_final[['p1_score', 'p2_score']] = df_final.apply(extract_player_scores, axis=1)? 关键原理说明
- splitlines() 保留结构语义:将 "4\n4\n6\n6" 正确拆为 ['4','4','6','6'],而非 split() 可能产生的 ['4','4','Game','Set',...] 干扰项;
- 位置即逻辑:在标准网球记分文本中,选手1的盘分先集中出现,选手2的盘分后集中出现,因此按行索引均分比交替取值更鲁棒;
- strip().isdigit() 安全过滤:兼顾空行和首尾空格,避免误判(如 " 4 " 或 "\n")。
⚠️ 注意事项
-
若存在三盘两胜制(3个数字)或五盘三胜制(5个数字),n // 2 会向下取整,导致分配偏差。此时需结合上下文(如选手姓名位置)做精准锚定,例如:
# 进阶:基于选手姓名定位得分块(更健壮) text = row['score'] p1_start = text.find('Altmaier') + len('Altmaier') p1_end = text.find('Kecmanovic') p2_start = p1_end + len('Kecmanovic') p2_end = text.rfind('Game Set and Match') p1_block = text[p1_start:p1_end].strip() p2_block = text[p2_start:p2_end].strip() p1_scores = " ".join(re.findall(r'\b\d+\b', p1_block)) p2_scores = " ".join(re.findall(r'\b\d+\b', p2_block)) 生产环境建议增加异常处理(如 try/except)和日志,对 numeric_lines 长度异常(非偶数、为空)提供默认值或告警。
通过坚持“结构驱动”而非“模式猜测”,该方案可稳定复现 p1_score = "4 4" 和 p2_score = "6 6" 的预期结果,为后续比分分析(如破发点计算、盘分趋势)奠定准确数据基础。










