分组Pandas DataFrame计算月度百分比差异遇问题求助
问题:按ID分组计算月度百分比差异失败
我已经在按ID分组的DataFrame中算出了两个月度数值的差值,但使用.pct_change()方法计算百分比差异时,要么出现KeyError,要么结果全为NaN。
我的DataFrame结构如下:
| ID | MONTH | TOTAL | Variance |
|---|---|---|---|
| REF1 | 1 | 55 | 0 |
| REF1 | 2 | 65 | 10 |
| REF1 | 3 | 66 | 1 |
| REF2 | 7 | 65 | -15 |
| REF2 | 6 | 80 | 10 |
| REF2 | 8 | 100 | 35 |
现有代码:
df_all = ( pd.concat(pd.read_excel("testdata.xlsx", header=None, sheet_name=None), ignore_index=True) .T.set_index(0).T .rename_axis(None, axis=1) .loc[:, ["ID", "DATE", "TOTAL"]] .assign(MONTH= lambda x: x["DATE"].dt.month) .groupby(by=["ID", "MONTH"], as_index=False).agg({"TOTAL":sum}) ) df_all['Variance'] = df_all['TOTAL'].sub( df_all[['ID', 'MONTH']] .merge(df_all.assign(MONTH=df_all['MONTH'].add(1)), how='left')['TOTAL'] ) df_all['Variance'].fillna(0, inplace=True)
解决方法
问题根源在于:.pct_change()默认按整列顺序计算,但你的数据未按ID和MONTH排序,且未分组,导致跨ID计算或顺序错乱,出现错误/NaN。
方法一:分组+排序后用.pct_change()
这是最简洁的实现方式:
# 1. 先按ID和MONTH排序,确保每个ID下的月份递增 df_all = df_all.sort_values(by=['ID', 'MONTH']) # 2. 按ID分组,计算每个ID内部的月度百分比变化 df_all['Pct_Change'] = df_all.groupby('ID')['TOTAL'].pct_change() # 3. 处理第一个月的NaN(按需填充为0或保留) df_all['Pct_Change'] = df_all['Pct_Change'].fillna(0) # 可选:转成百分比格式(保留两位小数) df_all['Pct_Change'] = df_all['Pct_Change'].apply(lambda x: f"{x*100:.2f}%")
方法二:沿用你的merge逻辑计算百分比
如果你想继续用merge方式实现:
import pandas as pd # 1. 生成上月数据的临时表,重命名TOTAL列 df_prev_month = df_all.assign(MONTH=df_all['MONTH'] + 1).rename(columns={'TOTAL': 'Prev_Total'}) # 2. 合并到原表,匹配相同ID和上月的MONTH df_all = df_all.merge(df_prev_month[['ID', 'MONTH', 'Prev_Total']], on=['ID', 'MONTH'], how='left') # 3. 计算百分比差异,处理空值和除数为0的情况 df_all['Pct_Change'] = df_all.apply( lambda row: (row['TOTAL'] - row['Prev_Total']) / row['Prev_Total'] if pd.notna(row['Prev_Total']) and row['Prev_Total'] != 0 else 0, axis=1 ) # 4. 移除临时列 df_all.drop('Prev_Total', axis=1, inplace=True)
内容的提问来源于stack exchange,提问作者Ryan1234
相关产品推荐
相关产品推荐

