pandas按ID分组根据SOURCE为A的NAME值新增全组CNAME列
解决方案
按ID分组填充对应SOURCE=A的NAME值有两种可直接运行的实现方式,输出结果完全匹配你的预期。
写法1:groupby.transform 分组广播实现
你之前用transform未达预期是因为内部逻辑没有把取到的目标值广播到全组,正确代码如下:
import pandas as pd df['CNAME'] = df.groupby('ID')['NAME'].transform( lambda group_col: group_col[df.loc[group_col.index, 'SOURCE'] == 'A'].iloc[0] )
逻辑说明
transform会保证分组计算后的返回结果和原DataFrame长度、索引完全对齐,可以直接赋值为新列- 每个分组内先筛选出
SOURCE == 'A'对应的NAME值,取到该值后会自动填充到当前ID下的所有行 - 如果存在部分ID没有SOURCE为A的记录,可以加判空逻辑避免报错:
def fetch_cname(group_col): target_val = group_col[df.loc[group_col.index, 'SOURCE'] == 'A'] return target_val.iloc[0] if len(target_val) > 0 else pd.NA df['CNAME'] = df.groupby('ID')['NAME'].transform(fetch_cname)
写法2:映射字典法(大数据量下性能更优)
不需要分组操作,先提取ID和对应A类NAME的映射关系,直接按ID匹配赋值即可,代码更简洁:
# 构造ID -> 对应SOURCE=A的NAME的映射字典 cname_mapping = df[df['SOURCE'] == 'A'].set_index('ID')['NAME'].to_dict() # 按ID映射赋值 df['CNAME'] = df['ID'].map(cname_mapping)
原写法问题说明
你之前尝试的df.groupby('ID').apply(lambda x: np.where(x['SOURCE'] == 'A', x['NAME'],' '))存在两个问题:
np.where仅给SOURCE为A的行返回NAME,其余行返回空字符串,没有把取到的A类NAME填充到同组其他行apply直接返回的是分组嵌套结构,没有和原df的索引做对齐,无法直接赋值为新列
运行上述任意一种写法,得到的输出和你给出的期望结果完全一致:
ID NAME SOURCE CNAME 0 1 ABC B AXY 1 1 ABC C AXY 2 1 AXY A AXY 3 2 XYZ B XYZ 4 2 XYZ A XYZ 5 3 SASA D SSA 6 3 SASA B SSA 7 3 SSA A SSA 8 3 SSA C SSA 9 4 BVA A BVA 10 4 BA B BVA 11 5 NAS A NAS 12 5 VAN B NAS
内容的提问来源于stack exchange,提问作者ankitpandey
相关产品推荐
相关产品推荐

