如何为DataFrame中无Year3的分组末尾添加指定数据行
优化实现:为缺失Year 3的产品分组补充数据
问题背景
原始DataFrame定义如下:
import pandas as pd List = [['2024-05-25', 'Group 1', 'Year 1', 23466882], ['2024-05-25', 'Group 1', 'Year 2', 458397284], ['2024-05-25', 'Group 1', 'Year 3', 2344545], ['2024-05-25', 'Group 2', 'Year 1', 6662345], ['2024-05-25', 'Group 2', 'Year 2', 46342], ['2024-05-25', 'Group 3', 'Year 1', 34234], ['2024-05-25', 'Group 3', 'Year 2', 45222]] df = pd.DataFrame(List, columns = ['Report_date', 'Product_group', 'Year', 'Sales'])
需求:针对每个Product_group,若不存在"Year 3"的行,则在该分组末尾添加一行数据,其中Sales固定为11000,Report_date和Product_group与该分组保持一致。
最初思路是拆分各分组逐个判断添加,但希望得到更高效的实现方案。
优化实现方案
方法1:透视表+堆叠补全(性能最优)
利用pandas的透视表将数据转为宽表,补全缺失的Year 3列后再转回长表,全程采用向量化操作,避免循环:
# 生成透视表,以Report_date和Product_group为索引,Year为列 pivot_df = df.pivot(index=['Report_date', 'Product_group'], columns='Year', values='Sales') # 为缺失Year 3的分组填充默认值11000 pivot_df['Year 3'] = pivot_df['Year 3'].fillna(11000) # 转回长表并重置索引 result_df = pivot_df.stack().reset_index(name='Sales') # 按分组和年份排序,保持原数据的顺序逻辑(可选) result_df = result_df.sort_values(['Product_group', 'Year'], ignore_index=True)
方法2:生成全量组合后合并(逻辑清晰)
先构造所有Product_group与目标年份的笛卡尔积组合,再与原数据左合并,填充缺失值:
# 获取所有唯一的Report_date和Product_group组合 group_date_pairs = df[['Report_date', 'Product_group']].drop_duplicates() # 定义需要覆盖的年份列表 target_years = ['Year 1', 'Year 2', 'Year 3'] # 生成全量组合(笛卡尔积) full_combinations = group_date_pairs.assign(key=1) \ .merge(pd.DataFrame({'Year': target_years, 'key': 1}), on='key') \ .drop('key', axis=1) # 与原数据左合并,填充缺失的Sales值 result_df = full_combinations.merge(df, on=['Report_date', 'Product_group', 'Year'], how='left') result_df['Sales'] = result_df['Sales'].fillna(11000) # 排序整理结果 result_df = result_df.sort_values(['Product_group', 'Year'], ignore_index=True)
方法3:GroupBy+Apply(逻辑直观)
如果偏好分组处理的逻辑,可通过groupby结合apply批量处理,相比手动拆分分组更简洁:
def supplement_year3(group): if 'Year 3' not in group['Year'].values: # 构造补充行,复用分组的Report_date和Product_group supplement_row = pd.DataFrame({ 'Report_date': [group['Report_date'].iloc[0]], 'Product_group': [group['Product_group'].iloc[0]], 'Year': ['Year 3'], 'Sales': [11000] }) return pd.concat([group, supplement_row], ignore_index=True) return group # 分组处理并合并结果 result_df = df.groupby('Product_group', group_keys=False).apply(supplement_year3).reset_index(drop=True)
方案对比
- 方法1和方法2采用向量化操作,在数据量较大时性能远优于循环/手动拆分,推荐用于大规模数据集。
- 方法3逻辑更直观,适合小规模数据或需要保留分组处理逻辑的场景。
内容的提问来源于stack exchange,提问作者Laura
相关产品推荐
相关产品推荐

