如何将DataFrame索引中的小计标签拆分至列并清理合并字符串?
解决DataFrame小计行的索引拆分与字符串清理问题
问题描述
我有一个包含多列的大型DataFrame,在创建列小计行时遇到两个问题:
- 小计行的标识标签位于索引而非DataFrame的列中
- 求和操作导致非数值列合并成了字符串
我的目标:
- 拆分索引中的小计标识字符串,将对应内容放入指定列
- 清除小计行最右侧非数值列中的合并字符串
原始代码
import pandas as pd df = pd.DataFrame( {'Status':['Active','Active','Inactive','Active'], 'Source':['Domestic','International','International','Restricted'], 'Activity':['In Progress','Post','Post','In Progress'], 'FY20':[2,55,52,99],'FY21':[90,20,11,43],'FY22':[10,52,57,9]}) # 排序设置 df['Status'] = pd.Categorical(df['Status'],categories= ['Inactive','Active']) df = df.sort_values('Status') df['Source'] = pd.Categorical(df['Source'],categories= ['International','Restricted','Domestic']) df = df.sort_values('Source') # 计算列的总和并添加小计行 df.loc['Active - In Progress Subtotal'] = df.loc[(df['Status'].isin(['Active'])) & (df['Activity'].isin(['In Progress']))].sum(axis=0)
期望输出
最终得到的DataFrame需要将小计信息放入对应列,且非数值列无合并字符串,排序后结果如下:
import pandas as pd df = pd.DataFrame( {'Status':['Active','Active','Inactive','Active','Active'], 'Source':['Domestic','International','International','Restricted','In Progress Subtotal'], 'Activity':['In Progress','Post','Post','In Progress',""], 'FY20':[2,55,52,99,101],'FY21':[90,20,11,43,133],'FY22':[10,52,57,9,19]}) df['Status'] = pd.Categorical(df['Status'],categories= ['Inactive','Active']) df = df.sort_values('Status') df['Source'] = pd.Categorical(df['Source'],categories= ['International','Restricted','Domestic','In Progress Subtotal']) df = df.sort_values('Source')
解决方案
核心思路
- 仅对数值列执行求和操作,避免非数值列被合并为字符串
- 手动构造小计行的非数值列内容,直接将拆分后的标识放入对应列
- 更新分类变量,确保小计行排序位置正确
修正后的完整代码
import pandas as pd # 初始化原始DataFrame df = pd.DataFrame( {'Status':['Active','Active','Inactive','Active'], 'Source':['Domestic','International','International','Restricted'], 'Activity':['In Progress','Post','Post','In Progress'], 'FY20':[2,55,52,99],'FY21':[90,20,11,43],'FY22':[10,52,57,9]}) # 设置初始分类排序规则 df['Status'] = pd.Categorical(df['Status'], categories=['Inactive','Active']) df['Source'] = pd.Categorical(df['Source'], categories=['International','Restricted','Domestic']) df = df.sort_values(['Status', 'Source']) # 筛选目标行并仅对数值列求和 filter_condition = (df['Status'] == 'Active') & (df['Activity'] == 'In Progress') subtotal_numeric = df.loc[filter_condition, ['FY20', 'FY21', 'FY22']].sum(axis=0) # 构造完整的小计行数据 subtotal_row = pd.Series({ 'Status': 'Active', 'Source': 'In Progress Subtotal', 'Activity': '', **subtotal_numeric.to_dict() }) # 将小计行添加到DataFrame,忽略索引以保持连续性 df = pd.concat([df, subtotal_row.to_frame().T], ignore_index=True) # 更新Source的分类规则,加入小计标签 df['Source'] = pd.Categorical(df['Source'], categories=['International','Restricted','Domestic','In Progress Subtotal']) # 重新排序 df = df.sort_values(['Status', 'Source']) # 查看结果 print(df)
代码说明
- 数值列单独求和:仅对
FY20、FY21、FY22列求和,避免Status、Source等非数值列被sum操作合并为字符串 - 手动构造小计行:直接设置小计行的Status为
Active,Source为In Progress Subtotal,Activity为空字符串,完全匹配需求 - 连续索引维护:使用
pd.concat添加行并设置ignore_index=True,避免原方法中索引存标识的问题 - 分类规则更新:在Source的分类中加入小计标签,确保排序后小计行处于指定位置
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

