Pandas多层索引DataFrame重索引:补全指定层级缺失月份
解决方案:补全MultiIndex中的月份层级且保留有效组合
要实现补全指定索引层级(月份)的所有取值,同时避免生成无效的Grouping与Sub-Group组合,可以通过以下两种方式操作:
方法一:基于现有聚合结果重索引
先完成原有的聚合操作,再针对有效组合生成完整的月份索引进行重映射:
步骤1:执行原聚合操作
import numpy as np import pandas as pd # 原DataFrame构建逻辑 np.random.seed(5) size = 25 dict = {'Customer':np.random.choice( ['Bob'], size), 'Grouping': np.random.choice( ['Corn','Wheat','Soy'], size), 'Date':np.random.choice( pd.date_range('1/1/2018','12/12/2022', freq='D'), size), 'Data': np.random.randint(20,100, size=(size)) } df = pd.DataFrame(dict) df['Sub-Group'] = np.nan df.loc[df['Grouping'] == 'Corn', 'Sub-Group'] = np.random.choice(['White', 'Dry'], size=len(df[df['Grouping'] == 'Corn'])) df.loc[df['Grouping'] == 'Wheat', 'Sub-Group'] = np.random.choice(['SRW', 'HRW', 'SWW'], size=len(df[df['Grouping'] == 'Wheat'])) df.loc[df['Grouping'] == 'Soy', 'Sub-Group'] = np.random.choice(['Beans', 'Meal'], size=len(df[df['Grouping'] == 'Soy'])) df['Year'] = df.Date.dt.year # 执行聚合并将Year层级转为列 grouped_df = (df.groupby(['Customer','Grouping','Sub-Group', df['Date'].dt.month, 'Year']) .agg(Units=('Data', 'sum')) .unstack() .fillna(0) )
步骤2:生成有效组合+完整月份的索引
从现有聚合结果中提取有效的(Customer, Grouping, Sub-Group)组合(避免无效笛卡尔积),再为每个组合生成1-12月的完整索引:
# 获取所有有效的(Customer, Grouping, Sub-Group)唯一组合 valid_top_levels = grouped_df.index.droplevel(3).unique() # 生成包含所有月份的完整MultiIndex full_index = pd.MultiIndex.from_product( [valid_top_levels, range(1, 13)], names=grouped_df.index.names )
步骤3:重索引并填充0
# 补全缺失月份,空值填充0 result = grouped_df.reindex(full_index, fill_value=0)
方法二:从源数据层面补全组合(更彻底)
如果需要确保每个年份-月份的组合都被覆盖,可以先生成所有有效组合的空记录,再与原数据合并后聚合:
# 提取原数据中的唯一维度值 unique_customers = df['Customer'].unique() unique_group_subgroup = df[['Grouping', 'Sub-Group']].drop_duplicates() unique_years = df['Year'].unique() # 生成所有可能的(Customer, Grouping, Sub-Group, Year, Month)组合 full_combinations = pd.MultiIndex.from_product( [unique_customers, unique_group_subgroup.itertuples(index=False), unique_years, range(1,13)], names=['Customer', 'Grouping', 'Sub-Group', 'Year', 'Month'] ).to_frame(index=False) # 原数据添加Month列 df['Month'] = df['Date'].dt.month # 合并原数据,空值填充0 merged_df = pd.merge( full_combinations, df[['Customer','Grouping','Sub-Group','Year','Month','Data']], on=['Customer','Grouping','Sub-Group','Year','Month'], how='left' ).fillna(0) # 聚合并将Year转为列 result = merged_df.groupby(['Customer','Grouping','Sub-Group','Month','Year']) .agg(Units=('Data','sum')) .unstack(fill_value=0)
原有方法失败原因说明
- 第一种方法:仅单独对月份层级重索引,但如果某个(Customer, Grouping, Sub-Group)组合在原数据中完全没有对应月份的记录,该组合会被忽略;且生成的
rere仅包含2018年的月份,未覆盖完整的1-12月范围。 - 第二种方法:使用
pd.MultiIndex.from_product(x.index.levels)会生成所有层级的笛卡尔积,包括原数据中不存在的Grouping与Sub-Group组合(如Wheat+Dry),因此会出现无效记录。
内容的提问来源于stack exchange,提问作者keg5038
相关产品推荐
相关产品推荐

