You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于赛事规则与参赛数据计算足球运动员出生年份

基于参赛类别与赛季推导足球运动员出生年份的Pandas逻辑优化

规则与需求说明

出生年份映射规则

存在如下细分类别、赛季与出生年份的对应关系(Age为对应参赛年龄):

AgeCategory2023202220212020201920182017
19A32004200320022001200019991998
18A22005200420032002200120001999
17A12006200520042003200220012000
16B22007200620052004200320022001
15B12008200720062005200420032002
14C22009200820072006200520042003
13C12010200920082007200620052004
12D22011201020092008200720062005
11D12012201120102009200820072006

示例:2023赛季参加A3类别的球员出生年份为2004;2020赛季参加D2类别的球员出生年份为2008。

现有DataFrame字段

手头的DataFrame仅包含以下字段:

  • Player:球员姓名
  • Season:参赛赛季(如2023、2022等)
  • Category:参赛大类(仅A、B、C、D,无细分的A1、B2等)

赛事晋级规则

  • D类别最多参赛2赛季,之后需晋级至C类别
  • C类别最多参赛2赛季,之后需晋级至B类别
  • B类别最多参赛2赛季,之后需晋级至A类别
  • A类别最多可参赛3赛季

核心需求

编写函数,结合球员各赛季的参赛大类数据与晋级规则,推导其出生年份(同一球员的出生年份需统一)。对于缺失部分数据的情况(如仅单条2023赛季B类别记录),需返回类似2007 or 2008的结果。

示例目标输出

Player  Category  Season Year Birth
Charly  A         2023   2006
Andrew  A         2023   2005
Louis   A         2023   2004
Peter   B         2023   2007
Charly  B         2022   2006
Andrew  A         2022   2005
Louis   A         2022   2004
Louis   A         2021   2004
Andrew  B         2021   2005
Charly  B         2021   2006
Peter   B         2022   2007
Juan    A         2022   2003
Juan    A         2021   2003
Juan    A         2020   2003
Michael C         2023   2011
Michael D         2022   2011

现有问题代码

import pandas as pd

data = {
    'Player': ['Charly', 'Andrew', 'Louis', 'Peter', 'Charly', 'Andrew', 'Louis', 'Louis', 'Andrew', 'Charly',
               'Peter', 'Juan', 'Juan', 'Juan', 'Michael', 'Michael'],
    'Category': ['A', 'A', 'A', 'B', 'B', 'A', 'A', 'A', 'B', 'B', 'B', 'A', 'A', 'A', 'C', 'D'],
    'Season': [2023, 2023, 2023, 2023, 2022, 2022, 2022, 2021, 2021, 2021, 2022, 2022, 2021, 2020, 2023, 2022],

}

df = pd.DataFrame(data)

def year_birth(player, df):
    seasons_a = df[(df['Player'] == player) & (df['Category'] == 'A')]['Season']
    seasons_b = df[(df['Player'] == player) & (df['Category'] == 'B')]['Season']
    seasons_c = df[(df['Player'] == player) & (df['Category'] == 'C')]['Season']
    seasons_d = df[(df['Player'] == player) & (df['Category'] == 'D')]['Season']
    
    if len(seasons_a) >= 3:
        return 2003
    elif len(seasons_a) == 2:
        if len(seasons_b) >= 1:
            return 2004
        else:
            return 2005
    elif len(seasons_a) == 1:
        if len(seasons_b) >= 2:
            return 2005
        else:
            return 2006
    elif len(seasons_b) >= 2:
        return 2006
    elif len(seasons_b) == 1:
        return 2007
    elif len(seasons_c) >= 2:
        return 2008
    elif len(seasons_d) == 1:
        return 2009
    else:
        return None

df['Year Birth'] = df.apply(lambda row: year_birth(row['Player'], df), axis=1)

print(df)

优化方案

问题分析

现有代码存在以下缺陷:

  1. 硬编码出生年份,未结合赛季动态计算,无法适配不同赛季的映射关系
  2. 仅统计各类别参赛次数,未考虑赛季先后顺序与晋级规则的关联
  3. 未处理缺失数据的模糊匹配场景

优化代码实现

import pandas as pd

# 1. 构建映射表数据并转换为结构化查询格式
mapping_data = [
    [19, 'A3', 2004, 2003, 2002, 2001, 2000, 1999, 1998],
    [18, 'A2', 2005, 2004, 2003, 2002, 2001, 2000, 1999],
    [17, 'A1', 2006, 2005, 2004, 2003, 2002, 2001, 2000],
    [16, 'B2', 2007, 2006, 2005, 2004, 2003, 2002, 2001],
    [15, 'B1', 2008, 2007, 2006, 2005, 2004, 2003, 2002],
    [14, 'C2', 2009, 2008, 2007, 2006, 2005, 2004, 2003],
    [13, 'C1', 2010, 2009, 2008, 2007, 2006, 2005, 2004],
    [12, 'D2', 2011, 2010, 2009, 2008, 2007, 2006, 2005],
    [11, 'D1', 2012, 2011, 2010, 2009, 2008, 2007, 2006]
]
mapping_df = pd.DataFrame(mapping_data, columns=['Age', 'Category', 2023, 2022, 2021, 2020, 2019, 2018, 2017])

# 建立年龄到大类的映射关系
age_to_main_cat = {}
for _, row in mapping_df.iterrows():
    age_to_main_cat[row['Age']] = row['Category'][0]

# 定义各品类参赛次数上限
cat_max_seasons = {'A':3, 'B':2, 'C':2, 'D':2}
# 定义品类晋级顺序(用于判断是否降级)
cat_order = {'D':0, 'C':1, 'B':2, 'A':3}

def get_birth_year(player, df):
    # 获取该球员所有参赛记录,按赛季升序排序
    player_records = df[df['Player'] == player].sort_values('Season').reset_index(drop=True)
    if len(player_records) == 0:
        return None
    
    # 确定可能的出生年范围(从映射表的最小到最大出生年)
    min_year = mapping_df[2023].min()
    max_year = mapping_df[2023].max()
    valid_years = []

    # 枚举所有可能的出生年,逐一验证是否符合规则
    for birth_year in range(min_year, max_year + 1):
        valid = True
        cat_counts = {'A':0, 'B':0, 'C':0, 'D':0}
        prev_cat_level = -1
        prev_age = -1

        for _, record in player_records.iterrows():
            season = record['Season']
            record_cat = record['Category']
            age = season - birth_year

            # 检查年龄是否在映射表范围内
            if age not in age_to_main_cat:
                valid = False
                break
            # 检查年龄对应的大类是否与记录一致
            if age_to_main_cat[age] != record_cat:
                valid = False
                break
            # 检查当前品类参赛次数是否超限
            cat_counts[record_cat] += 1
            if cat_counts[record_cat] > cat_max_seasons[record_cat]:
                valid = False
                break
            # 检查是否出现降级(比如从B类回到D类)
            current_cat_level = cat_order[record_cat]
            if current_cat_level < prev_cat_level:
                valid = False
                break
            # 检查年龄是否随赛季递增
            if age <= prev_age:
                valid = False
                break

            prev_cat_level = current_cat_level
            prev_age = age

        if valid:
            valid_years.append(birth_year)
    
    # 处理结果输出
    if len(valid_years) == 1:
        return valid_years[0]
    elif len(valid_years) > 1:
        return ' or '.join(map(str, sorted(valid_years)))
    else:
        return None

# 按球员分组计算出生年,保证同一球员结果统一
df['Year Birth'] = df.groupby('Player')['Player'].transform(lambda x: get_birth_year(x.iloc[0], df))

print(df)

代码说明

  1. 结构化映射:将原始映射表转换为年龄与大类的对应关系,便于快速校验
  2. 枚举验证逻辑:遍历所有可能的出生年,逐一验证是否符合参赛记录、晋级规则(无降级、次数不超限)、年龄递增要求
  3. 统一结果处理:通过groupby对每个球员单独计算,确保同一球员的出生年一致;支持多结果的模糊输出格式
  4. 适配全场景:既覆盖完整参赛记录的准确推导,也支持缺失数据的模糊匹配

内容的提问来源于stack exchange,提问作者nokvk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 02:27:07