You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中计算费率变更前后Price列平均值(排除变更当月)

计算费率变更前后Price平均值(排除变更当月)

需求说明

针对给定DataFrame完成以下操作:

  • 按**客户(若含产品ID则按客户+产品ID)**分组,计算费率(Rate)变更前后Price列的平均值
  • 排除费率变更当月的数值,不纳入前后平均值计算(例如XY Ltd8月变更费率,变更前取6、7月数据平均,变更后取9、10月数据平均)
  • 新增两列:
    1. New Column:对应行所属阶段的平均值(变更前填变更前平均,变更当月填0,变更后填变更后平均)
    2. New column 2:统一为「变更后平均值 - 变更前平均值」的差值,同一分组内所有行取值一致

已尝试代码(无法满足需求)

用户尝试了以下代码,但无法实现排除变更当月的逻辑,也无法计算前后差值:

df['New Column'] =  df.groupby(['Client', 'Rate'])['Price'].transform('mean')

示例数据

DateClientRatePrice
2022-06-01XY Ltd1.505
2022-07-01XY Ltd1.506
2022-08-01XY Ltd3.0010
2022-09-01XY Ltd3.00-3
2022-10-01XY Ltd3.00-5
2022-06-01ZZ Inc1.603
2022-07-01ZZ Inc1.604
2022-08-01ZZ Inc4.0012
2022-09-01ZZ Inc4.00-4
2022-10-01ZZ Inc4.00-6

期望输出

DateClientRatePriceNew ColumnNew column 2
2022-06-01XY Ltd1.5055.5-9.5
2022-07-01XY Ltd1.5065.5-9.5
2022-08-01XY Ltd3.00100.0-9.5
2022-09-01XY Ltd3.00-3-4.0-9.5
2022-10-01XY Ltd3.00-5-4.0-9.5
2022-06-01ZZ Inc1.6033.5-8.5
2022-07-01ZZ Inc1.6043.5-8.5
2022-08-01ZZ Inc4.00120.0-8.5
2022-09-01ZZ Inc4.00-4-5.0-8.5
2022-10-01ZZ Inc4.00-6-5.0-8.5

补充样本数据(含Prod ID)

DateClientProd IDRatePrice
2021-11-30LL Inco710-29
2021-11-30LL Inco731.6889
2021-11-30LL Inco741.6754
2021-11-30LL Inco751.62608
2021-12-31LL Inco710-31
2021-12-31LL Inco731.6916
2021-12-31LL Inco741.6777
2021-12-31LL Inco751.62688

解决方案代码

核心逻辑

  1. 转换日期格式并分组识别费率变更的日期
  2. 标记每行数据所属的阶段(变更前、变更当月、变更后)
  3. 分别计算各分组的变更前、变更后Price平均值
  4. 映射填充目标列,计算差值

完整代码

import pandas as pd

# 示例数据读取(实际使用时替换为你的数据加载方式)
df = pd.DataFrame({
    'Date': ['2022-06-01', '2022-07-01', '2022-08-01', '2022-09-01', '2022-10-01',
             '2022-06-01', '2022-07-01', '2022-08-01', '2022-09-01', '2022-10-01'],
    'Client': ['XY Ltd']*5 + ['ZZ Inc']*5,
    'Rate': [1.5, 1.5, 3.0, 3.0, 3.0, 1.6, 1.6, 4.0, 4.0, 4.0],
    'Price': [5,6,10,-3,-5,3,4,12,-4,-6]
})

# 1. 处理日期列
df['Date'] = pd.to_datetime(df['Date'])

# 2. 设置分组键:若使用含Prod ID的数据集,改为group_keys = ['Client', 'Prod ID']
group_keys = ['Client']

# 3. 找出每个分组内的费率变更日期
def get_change_date(group):
    group = group.sort_values('Date')
    # 标记Rate发生变化的行
    group['Rate_Change'] = group['Rate'].ne(group['Rate'].shift())
    # 取第一个变更的日期(排除初始行的默认变化标记)
    change_dates = group[(group['Rate_Change']) & (group.index != group.index[0])]['Date']
    return change_dates.iloc[0] if not change_dates.empty else None

change_dates = df.groupby(group_keys).apply(get_change_date).reset_index(name='Change_Date')
df = df.merge(change_dates, on=group_keys, how='left')

# 4. 标记数据所属阶段
df['Stage'] = pd.cut(
    df['Date'],
    bins=[pd.Timestamp.min, df['Change_Date'], pd.Timestamp.max],
    labels=['Before', 'Change_Month', 'After'],
    include_lowest=True
)
# 无变更的分组统一标记为变更前
df.loc[df['Change_Date'].isna(), 'Stage'] = 'Before'

# 5. 计算变更前后的平均值
before_mean = df[df['Stage'] == 'Before'].groupby(group_keys)['Price'].mean().reset_index(name='Before_Mean')
after_mean = df[df['Stage'] == 'After'].groupby(group_keys)['Price'].mean().reset_index(name='After_Mean')

df = df.merge(before_mean, on=group_keys, how='left')
df = df.merge(after_mean, on=group_keys, how='left')

# 6. 填充目标列
df['New Column'] = df.apply(
    lambda x: x['Before_Mean'] if x['Stage'] == 'Before'
    else (x['After_Mean'] if x['Stage'] == 'After' else 0.0),
    axis=1
)
# 无变更的分组差值为0
df['New column 2'] = df['After_Mean'].fillna(0) - df['Before_Mean'].fillna(0)

# 整理输出列顺序
df = df[['Date', 'Client', 'Rate', 'Price', 'New Column', 'New column 2']]

print(df)

适配含Prod ID的数据集

只需将代码中的group_keys改为:

group_keys = ['Client', 'Prod ID']

即可实现按客户+产品ID分组处理,适配补充样本数据的场景。

内容的提问来源于stack exchange,提问作者ross jim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:05:33