使用Pandas按work分组,基于actual与target生成cost_met列的技术咨询
实现cost_met列的逻辑代码修改方案
原始DataFrame数据
work cost actual target 0 A 2 14 56.0 1 B 2 21 67.0 2 B 3 32 67.0 3 B 4 32 NaN 4 A 3 56 56.0 5 A 4 82 NaN
需求规则
- 按
work列分组,每组的target值要么全为null,要么为唯一非null值 - 若
actual >= target(target非null时),cost_met取组内满足该条件的基准cost - 若
actual < target,取同组对应场景的指定cost(如B组actual=32的两行取第一个cost=3,组内其他行沿用该值)
预期输出
work cost actual target cost_met 0 A 2 14 56.0 3 1 B 2 21 67.0 3 2 B 3 32 67.0 3 3 B 4 32 NaN 3 4 A 3 56 56.0 3 5 A 4 82 NaN 3
已尝试代码
grouped_df = df_final1.groupby('work') df_final1['new_column']=grouped_df.apply(lambda x: x['cost'].where(x['actual']>x['target'])).reset_index(drop=True)
修改后的代码实现
调整分组逻辑,为每个分组确定统一的基准cost后批量赋值:
import pandas as pd # 加载原始数据(如果已有可跳过) df_final1 = pd.DataFrame({ 'work': ['A', 'B', 'B', 'B', 'A', 'A'], 'cost': [2, 2, 3, 4, 3, 4], 'actual': [14, 21, 32, 32, 56, 82], 'target': [56.0, 67.0, 67.0, None, 56.0, None] }) def process_group(group): # 筛选target非空的行,检查是否存在actual >= target的记录 valid_target_rows = group[group['target'].notna()] met_condition = valid_target_rows[valid_target_rows['actual'] >= valid_target_rows['target']] if not met_condition.empty: # 取第一个满足条件的cost作为组基准 base_cost = met_condition['cost'].iloc[0] else: # 找到组内出现次数最多的actual值,取其对应的第一个cost most_freq_actual = group['actual'].value_counts().idxmax() base_cost = group[group['actual'] == most_freq_actual]['cost'].iloc[0] # 为组内所有行设置cost_met group['cost_met'] = base_cost return group # 分组处理并重置索引 df_final1 = df_final1.groupby('work').apply(process_group).reset_index(drop=True) print(df_final1)
代码逻辑说明
- 分组处理:按
work分组后,对每个组单独计算基准cost - 优先取满足条件的cost:如果组内存在
actual >= target的行,直接取第一个这类行的cost作为整个组的cost_met值 - 无满足条件时的兜底逻辑:如果组内没有符合
actual >= target的行,找到组内出现次数最多的actual值,取该值对应的第一个cost作为基准 - 统一赋值:将基准cost赋值给组内所有行的
cost_met列,匹配预期输出结果
内容的提问来源于stack exchange,提问作者workpyspark
相关产品推荐
相关产品推荐

