基于同组已有值按条件填充Pandas DataFrame的Code列
问题描述
现有如下Pandas DataFrame:
import pandas as pd df = pd.DataFrame({'Make': ['Tesla','Tesla','Tesla','Toyota','Ford','Ford','Ford','BMW','BMW','BMW','Mercedes','Mercedes','Mercedes'], 'Type': ['Model X','Model X','Model X','Corolla','Bronco','Bronco','Mustang','3 Series','3 Series','7 Series','C-Class','C-Class','S-Class'], 'Year': [2015, 2015, 2015, 2017, 2018, 2018, 2020, 2015, 2015, 2017, 2018, 2018, 2020], 'Price': [85000, 90000, 95000, 20000, 35000, 35000, 45000, 40000, 40000, 65000, 50000, 50000, 75000], 'Color': ['White','White','White','Red','Blue','Blue','Yellow','Silver','Silver','Black','White','White','Black'], 'Code' : ['TSLABG','TSLA',None,'TYTA','FRD','_BG',None,None,'BMW','BMW','MercedesBG','Mercedes_BG','MercedesBG'] })
原始数据展示:
| Make | Type | Year | Price | Color | Code |
|---|---|---|---|---|---|
| Tesla | Model X | 2015 | 85000 | White | TSLABG |
| Tesla | Model X | 2015 | 90000 | White | TSLA |
| Tesla | Model X | 2015 | 95000 | White | None |
| Toyota | Corolla | 2017 | 20000 | Red | TYTA |
| Ford | Bronco | 2018 | 35000 | Blue | FRD |
| Ford | Bronco | 2018 | 35000 | Blue | _BG |
| Ford | Mustang | 2020 | 45000 | Yellow | None |
| BMW | 3 Series | 2015 | 40000 | Silver | None |
| BMW | 3 Series | 2015 | 40000 | Silver | BMW |
| BMW | 7 Series | 2017 | 65000 | Black | BMW |
| Mercedes | C-Class | 2018 | 50000 | White | MercedesBG |
| Mercedes | C-Class | 2018 | 50000 | White | Mercedes_BG |
| Mercedes | S-Class | 2020 | 75000 | Black | MercedesBG |
需求说明
- 基于Make列更新Code列,若Code列存在
None值,使用同Make组内的其他Code值填充 - 若同组内存在带
BG或_BG后缀的Code值,该组所有Code值需统一添加对应后缀
规则示例
- BMW组无BG/_BG后缀,填充None后仍为BMW
- Ford组存在FRD和_BG,需统一为FRD_BG
- Mercedes组需统一为Mercedes_BG
尝试的代码及问题
尝试使用以下代码处理:
code = (df['Code'].str.split('(_)', expand=True).add_prefix('part').replace('-', None).groupby(df['Make']).transform('first').fillna('').agg(''.join, axis=1)) df['Code'] = code df
但输出中Mercedes组的Code为MercedesBG_BG,不符合预期的Mercedes_BG,需修正代码以得到目标输出。
解决方案
我们需要先提取每组的基础代码和后缀类型,再统一拼接。修正后的代码如下:
def process_group(group): # 获取组内非空的Code值 codes = group['Code'].dropna() if codes.empty: return group['Code'] base_codes = [] suffix = '' # 遍历组内有效Code,识别基础部分和标准后缀 for code in codes: if code.endswith('_BG'): base_codes.append(code[:-3]) suffix = '_BG' elif code.endswith('BG'): base_codes.append(code[:-2]) # 组内存在_BG后缀时优先选用 if any(c.endswith('_BG') for c in codes): suffix = '_BG' else: suffix = 'BG' else: base_codes.append(code) # 检查组内是否有带后缀的Code,确定统一后缀 if any(c.endswith(('BG', '_BG')) for c in codes): suffix = '_BG' if any(c.endswith('_BG') for c in codes) else 'BG' # 取出现次数最多的基础代码作为组内标准基础 standard_base = pd.Series(base_codes).mode()[0] # 为整组生成统一Code group['Code'] = standard_base + suffix return group # 按Make分组处理 df = df.groupby('Make', group_keys=False).apply(process_group)
处理后的结果:
| Make | Type | Year | Price | Color | Code |
|---|---|---|---|---|---|
| Tesla | Model X | 2015 | 85000 | White | TSLA_BG |
| Tesla | Model X | 2015 | 90000 | White | TSLA_BG |
| Tesla | Model X | 2015 | 95000 | White | TSLA_BG |
| Toyota | Corolla | 2017 | 20000 | Red | TYTA |
| Ford | Bronco | 2018 | 35000 | Blue | FRD_BG |
| Ford | Bronco | 2018 | 35000 | Blue | FRD_BG |
| Ford | Mustang | 2020 | 45000 | Yellow | FRD_BG |
| BMW | 3 Series | 2015 | 40000 | Silver | BMW |
| BMW | 3 Series | 2015 | 40000 | Silver | BMW |
| BMW | 7 Series | 2017 | 65000 | Black | BMW |
| Mercedes | C-Class | 2018 | 50000 | White | Mercedes_BG |
| Mercedes | C-Class | 2018 | 50000 | White | Mercedes_BG |
| Mercedes | S-Class | 2020 | 75000 | Black | Mercedes_BG |
代码说明
- 优先识别并选用
_BG作为统一后缀(如果组内存在),避免重复拼接后缀的问题 - 使用众数确定组内标准基础代码,确保基础部分的准确性
- 为整组统一生成Code,保证同组内所有值一致且符合需求
内容的提问来源于stack exchange,提问作者Sudeep George
相关产品推荐
相关产品推荐

