如何基于指定行首个非零值重排Pandas DataFrame
问题描述
现有一个记录不同开业时间店铺的销售、成本数据的Pandas DataFrame,列是月份。需要基于各店铺Sales行首个非零值所在月份重排列,使列顺序变为开业后第1个销售月、第2个销售月……以便统一对比各店铺的首月及后续业绩。
示例原始数据(修正后可运行版本):
import pandas as pd data = [ ['Store 1', 'Sales', 0.0, 0.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], ['Store 1', 'Costs', 0.0, 0.0, 0.0, 3.0, 1.0, 1.0, 7.0, 0.0], ['Store 2', 'Sales', 0.0, 0.0, 0.0, 0.0, 15.0, 16.0, 17.0, 18.0] ] columns = ['Store', 'Metric', 'Jan-19', 'Feb-19', 'Mar-19', 'Apr-19', 'May-19', 'June-19', 'Jul-19', 'Aug-19'] df = pd.DataFrame(data, columns=columns) df = df.set_index(['Store', 'Metric'])
期望重排后效果:
A B C D E F Store 1 Sales 3.0 4.0 5.0 6.0 7.0 8.0 Store 1 Costs 0.0 3.0 1.0 1.0 7.0 0.0 Store 2 Sales 15.0 16.0 17.0 18.0 NaN NaN
解决思路与代码
核心思路是按店铺分组,找到每个店铺Sales行的首个非零列位置,然后从该位置开始截取所有后续列,最后统一重命名列名。
步骤1:定义分组处理函数
def align_store_columns(group): # 提取当前店铺的Sales行数据 sales_row = group.xs('Sales', level='Metric') # 找到首个非零值对应的列索引 first_non_zero_col = sales_row.ne(0).idxmax() # 从该列开始截取所有后续列 aligned_data = group.loc[:, first_non_zero_col:] # 将列名重命名为A、B、C... aligned_data.columns = [chr(ord('A') + i) for i in range(len(aligned_data.columns))] return aligned_data
步骤2:分组应用并合并结果
# 按店铺分组处理,合并结果 result = df.groupby('Store', group_keys=False).apply(align_store_columns) # 重置索引(可选,方便查看结构化数据) result = result.reset_index() print(result)
代码说明
sales_row.ne(0).idxmax():ne(0)生成布尔数组(非零为True),idxmax()返回第一个True对应的列名,即首个有销售数据的月份。- 按店铺分组后,每个店铺的所有指标(Sales、Costs等)都从该月份开始截取,保证同一店铺的指标列对齐到开业后的时间节点。
- 列名重命名为A、B、C...,实现不同店铺的首月、次月数据统一列名对比。
补充说明
你之前尝试的代码是获取首个非零值,而我们需要的是该值所在的列位置,这是实现列重排的关键——只有找到起始列,才能截取后续的月份数据完成对齐。
内容的提问来源于stack exchange,提问作者bbbb
相关产品推荐
相关产品推荐

