将函数应用于分组和滚动组

问题描述 投票:0回答:2

给定一个 pandas 数据框,将其按 3 个级别进行分组,并应用一个滚动地采用两列作为参数的函数:

创建数据框的代码:

import pandas as pd
import numpy as np
df_index = pd.DataFrame({
    'classes': ['A']*3*3 +  ['B']*3*3 +['C']*3*3,
    'names': ['Alex']*3 + ['Alan']*3 + ['Ash']*3 + ['Bart']*3 + ['Blake']*3 + ['Beth']*3 + ['Charlie']*3 + ['Cristine']*3 + ['Cameron']*3,
    'numbers': [0, 1, 2] * 9
})

df_values = pd.DataFrame(data=np.random.normal(), index=pd.date_range(start='2020-01-01', end='2024-01-01'), columns=['net', 'gross']).rename_axis('date').reset_index(drop=False)

df = pd.DataFrame()
for i in range(len(df_index)):
    _df = df_values.copy()
    _df['classes'] = df_index.iloc[i]['classes']
    _df['names'] = df_index.iloc[i]['names']
    _df['numbers'] = df_index.iloc[i]['numbers']
    df = pd.concat((df, _df), axis=0)

df.set_index(['classes','names','numbers','date'], inplace=True)

部分功能:

def fun(net, gross):
    return net.mean() / gross.std()

以下内容不起作用。我正在寻找 groupby,并滚动应用“fun()”:

df.groupby(['classes', 'names', 'numbers']).rolling(window=500).apply(
    lambda x: fun(net=x['net'], gross=x['gross'])  
)

谢谢。

PS:真正的 fun() 比这里的复杂得多,所以我无法直接向 groupby 计算“.mean()”和“.std()”。

python pandas group-by apply rolling-computation
2个回答
0
投票

rolling.apply
按列进行操作,因此无法直接使用多列。

相反,您可以对one列进行切片,并通过根据窗口的索引对原始DataFrame进行切片来使用副作用:

(df.groupby(['classes', 'names', 'numbers']).rolling(window=500)['net']
   .apply(lambda x: fun(net=df.loc[x.index, 'net'],
                        gross=df.loc[x.index, 'gross']))
)

但请注意,操作可能会非常慢!


0
投票

如评论所述,

.groupby().rolling().apply()
适用于列,因此您无权访问
groupby
中的其他列。您可以尝试取消堆叠组索引并在宽数据帧上滚动:

wide_df = df.unstack(['classes','names','numbers'])

fun(wide_df['net'].dropna().rolling(5).mean(), wide_df['gross'].dropna().rolling(5).std())
© www.soinside.com 2019 - 2024. All rights reserved.