如何基于Match Quality聚合GroupBy结果并处理NaN,lambda能否关联对应列
问题描述
编辑补充:删除NaN行不可行,因为并非所有分组都有Match Quality值,但仍需提取这些分组中的定价数据。
现有如下DataFrame:
import numpy as np import pandas as pd df = pd.DataFrame({ 'Part Description':['Clutch Set', 'Clutch Set', 'Clutch Set', 'Clutch Set', 'Cambelt Kit', 'Cambelt Kit', 'Cambelt Kit', 'Cambelt Kit', 'Front Bumper', 'Front Bumper'], 'Price':[100, np.nan, np.nan, 50, 1000, np.nan, 500, np.nan, 250, np.nan], 'Match Quality':['Poor', np.nan, np.nan, np.nan, np.nan, np.nan, 'Perfect', np.nan, np.nan, np.nan] })
需求:按Part Description分组并聚合Price列,规则为:
- 优先选择
Match Quality非空对应的Price值; - 若分组内
Match Quality全为NaN,则选择该分组的最高Price值。
期望输出结果:
pd.DataFrame({ 'Part Description':['Clutch Set', 'Cambelt Kit', 'Front Bumper'], 'Price':[100, 500, 250], 'Match Quality':['Poor', 'Perfect', np.nan] })
尝试用aggregate结合lambda函数实现,但不确定能否在lambda中引用Price对应的Match Quality值:
df.groupby(['Part Description']).agg(lambda x: ... )
解决方案
直接用agg的lambda单独处理Price列时,无法直接引用同一行的Match Quality值——因为lambda接收的是单列的Series,只能访问当前列的数据。推荐用groupby.apply实现,它能让你拿到整个分组的DataFrame,可同时操作多列,逻辑更清晰:
def process_group(group): # 筛选出Match Quality非空的行 match_rows = group[group['Match Quality'].notna()] if not match_rows.empty: # 取第一个有效匹配的Price和Match Quality(若有多条可按需调整规则) return pd.Series({ 'Price': match_rows['Price'].iloc[0], 'Match Quality': match_rows['Match Quality'].iloc[0] }) else: # 分组无有效匹配时,取最高Price,Match Quality设为NaN return pd.Series({ 'Price': group['Price'].max(), 'Match Quality': np.nan }) # 应用分组处理并重置索引 result = df.groupby('Part Description').apply(process_group).reset_index() print(result)
输出结果:
Part Description Price Match Quality 0 Cambelt Kit 500.0 Perfect 1 Clutch Set 100.0 Poor 2 Front Bumper 250.0 NaN
如果一定要用agg,可以先构造临时列打包Price和Match Quality,再对元组列聚合,但可读性较差:
# 构造包含Price和Match Quality的元组列 df['price_match'] = df.apply(lambda row: (row['Price'], row['Match Quality']), axis=1) def agg_func(tuples): # 过滤出Match Quality非空的元组 valid_tuples = [t for t in tuples if pd.notna(t[1])] if valid_tuples: return valid_tuples[0] else: # 取Price最大值对应的元组 max_price = max([t[0] for t in tuples if pd.notna(t[0])]) return (max_price, np.nan) # 聚合后拆分元组为列 result = df.groupby('Part Description')['price_match'].agg(agg_func)\ .apply(pd.Series)\ .rename(columns={0:'Price', 1:'Match Quality'})\ .reset_index()
对比来看,groupby.apply的方式逻辑更直观,后续维护也更方便。
内容的提问来源于stack exchange,提问作者Elliott Davey
相关产品推荐
相关产品推荐

