如何在Pandas DataFrame中按质量条件设置分组极值?
解决方案:带质量条件的DataFrame分组值替换
问题背景
给定如下示例DataFrame:
import pandas as pd lst = [['PF2', 'E1', -500, -127, 199971, 200164, True, True], ['PR2', 'E1', -500, -167, 199655, 200124, True, True], ['PF2', 'E1', -500, -167, 199645, 200124, False, True], ['PF2', 'E1', -400, -127, 199971, 200564, True, True], ['PR2', 'E1', -400, -167, 199155, 200324, True, True]] df = pd.DataFrame(lst, columns=["Name", "Part", "Rel_s", "Rel_e", "Abs_s", "Abs_e", "Quality_Start", "Quality_End"])
需求是:
- 将
Abs_s替换为Part+Rel_s分组中仅Quality_Start=True的数据的最小值;若分组内无符合条件的数据,保留原数值。 - 将
Abs_e替换为Part+Rel_e分组中仅Quality_End=True的数据的最大值;若分组内无符合条件的数据,保留原数值。
原代码未考虑质量条件,需要优化。
解决方案
方法1:分组映射法(简洁高效)
先筛选符合质量条件的数据计算分组统计值,再通过映射回填到原DataFrame,无匹配时保留原值:
# 计算符合Quality_Start=True的Part+Rel_s分组最小Abs_s abs_s_min = df[df['Quality_Start']].groupby(["Part", "Rel_s"])['Abs_s'].min() # 映射回原DataFrame,无对应分组则保留原Abs_s df['Abs_s'] = df.apply( lambda row: abs_s_min.get((row['Part'], row['Rel_s']), row['Abs_s']), axis=1 ) # 计算符合Quality_End=True的Part+Rel_e分组最大Abs_e abs_e_max = df[df['Quality_End']].groupby(["Part", "Rel_e"])['Abs_e'].max() # 映射回原DataFrame,无对应分组则保留原Abs_e df['Abs_e'] = df.apply( lambda row: abs_e_max.get((row['Part'], row['Rel_e']), row['Abs_e']), axis=1 )
验证结果:
对于Part=E1, Rel_s=-500的分组,符合Quality_Start=True的行是第0、1行,Abs_s最小值为199655,会替换该分组所有行的Abs_s(包括第2行原199645),完全符合需求。
方法2:transform结合条件筛选
直接在分组transform中加入质量判断,过滤不符合条件的数据后计算统计值,无有效数据时保留原值:
# 处理Abs_s:仅用Quality_Start=True的数据计算分组最小值 df['Abs_s'] = df.groupby(["Part", "Rel_s"])['Abs_s'].transform( lambda x: x.where(df.loc[x.index, 'Quality_Start']).min() ).fillna(df['Abs_s']) # 处理Abs_e:仅用Quality_End=True的数据计算分组最大值 df['Abs_e'] = df.groupby(["Part", "Rel_e"])['Abs_e'].transform( lambda x: x.where(df.loc[x.index, 'Quality_End']).max() ).fillna(df['Abs_e'])
逻辑说明:
x.where(df.loc[x.index, 'Quality_Start'])会将分组内Quality_Start=False的Abs_s设为NaN,分组计算min时自动忽略NaN;- 若分组内无符合条件的数据,
transform返回NaN,此时用fillna(df['Abs_s'])保留原数值。
内容的提问来源于stack exchange,提问作者Mz_Chen
相关产品推荐
相关产品推荐

