You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何将groupby.apply返回的自定义分组计算结果合并至原有DataFrame并在每组首行填充值

解决方案

要实现你想要的效果,我们可以分步骤精准完成:先计算每个日期分组的C、D值,再将这些值填充到原DataFrame对应日期组的第一行中,具体代码和解释如下:

import pandas as pd

# 定义自定义计算函数
def custFun(x):
    d = {}
    d['C'] = (x['A'] * x['B']).sum() / x['B'].sum()
    d['D'] = (x['B'] / x['A']).sum() / len(x)
    return pd.Series(d)

# 你的原始DataFrame
df = pd.DataFrame({
    'timestamp': ['2021-05-14 15:25:00', '2021-05-14 15:26:00', 
                  '2021-05-15 15:27:00', '2021-05-15 15:28:00', '2021-05-15 15:29:00'],
    'A': [1.70, 1.55, 1.10, 1.20, 1.50],
    'B': [1, 3, 4, 2, 2]
})
# 确保timestamp是datetime类型(如果原始数据不是的话)
df['timestamp'] = pd.to_datetime(df['timestamp'])

# 步骤1:新增日期列,简化分组匹配逻辑
df['date'] = df['timestamp'].dt.date

# 步骤2:按日期分组计算C、D值,重置索引方便后续赋值
grouped_results = df.groupby('date').apply(custFun).reset_index()

# 步骤3:提取每个日期组第一行的索引位置
first_row_indices = df.groupby('date').head(1).index

# 步骤4:将计算结果填充到对应位置,保留两位小数和示例格式一致
df.loc[first_row_indices, 'C'] = grouped_results['C'].round(2).values
df.loc[first_row_indices, 'D'] = grouped_results['D'].round(2).values

# 可选:删除临时的date列
df = df.drop('date', axis=1)

print(df)

代码细节解释

  • 新增date列是为了避免直接操作timestamp的复杂逻辑,让分组匹配更直观;
  • groupby('date').apply(custFun)会按日期批量计算每个组的C、D值,reset_index()把日期从索引转为普通列,方便后续精准赋值;
  • df.groupby('date').head(1).index精准定位每个日期组的第一行,这就是我们要填充C、D值的目标位置;
  • 最后用df.loc[]完成赋值,并用round(2)处理小数位数,和你期望的示例格式对齐。

运行后得到的结果和你要求的完全一致:

timestamp     A  B     C     D
0 2021-05-14 15:25:00  1.70  1  1.58  1.26
1 2021-05-14 15:26:00  1.55  3   NaN   NaN
2 2021-05-15 15:27:00  1.10  4  1.22  2.21
3 2021-05-15 15:28:00  1.20  2   NaN   NaN
4 2021-05-15 15:29:00  1.50  2   NaN   NaN

(注:pandas中空值显示为NaN,如果需要完全显示空白,可以追加df.fillna('', inplace=True)处理)

另外补充你提到的transform替代方案:

# 用transform的实现方式
df['date'] = df['timestamp'].dt.date
# 先给所有行填充分组的C、D值
df['C'] = df.groupby('date').transform(custFun)['C']
df['D'] = df.groupby('date').transform(custFun)['D']
# 清空非第一行的C、D值
mask = ~df.index.isin(df.groupby('date').head(1).index)
df.loc[mask, ['C', 'D']] = pd.NA
df = df.drop('date', axis=1)

不过这个方法会重复调用两次custFun,数据量大时效率不如第一种方案,因此更推荐第一种实现方式。

内容的提问来源于stack exchange,提问作者Dr.PB

火山引擎 最新活动